diff --git a/.gitattributes b/.gitattributes index 5c7f5b73b07..e7c2f838973 100644 --- a/.gitattributes +++ b/.gitattributes @@ -24,6 +24,10 @@ *.dll binary *.exe binary +# Test Resources +*.binary binary +*.output binary + # Files with Windows line endings VivoxAUP.txt text eol=crlf FILES_ARE_UNICODE_UTF-16LE.txt text eol=crlf diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5a5628ede2b..d17ff9d0d3b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -43,7 +43,7 @@ jobs: needs: setup strategy: matrix: - runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-2022","macos-15-xlarge"]') }} + runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge","linux-large"]' || '["windows-2022","macos-15-xlarge","ubuntu-22.04"]') }} configuration: ${{ fromJson(needs.setup.outputs.configurations) }} runs-on: ${{ matrix.runner }} outputs: @@ -90,6 +90,20 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.sha }} + - name: Linux Disk Cleanup + if: runner.os == 'Linux' + run: | + # Prune various unused files from linux builder to fix free runner disk space exhaustion + df -h + sudo docker container prune -f + sudo docker image prune -a -f + sudo rm -rf /usr/local/share/boost + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/local/lib/android + sudo rm -rf /opt/ghc + sudo rm -rf /usr/local/.ghcup + df -h + - name: Setup python uses: actions/setup-python@v5 with: @@ -120,6 +134,21 @@ jobs: ${{ runner.os }}-64-${{ matrix.configuration }}- ${{ runner.os }}-64- + - name: Install Linux dependencies + if: runner.os == 'Linux' + run: | + sudo apt update + sudo apt install -y \ + libpulse-dev libunwind-dev \ + libgl1-mesa-dev libglu1-mesa-dev libxinerama-dev \ + libxcursor-dev libxfixes-dev libgstreamer1.0-dev \ + libgstreamer-plugins-base1.0-dev ninja-build libxft-dev \ + llvm mold libpipewire-0.3-dev libdbus-1-dev libvlc-dev \ + libosmesa6-dev + sudo locale-gen en_US.UTF-8 + sudo locale-gen en_GB.UTF-8 + sudo locale-gen fr_FR.UTF-8 + - name: Determine source branch id: which-branch uses: secondlife/viewer-build-util/which-branch@v2 @@ -425,20 +454,26 @@ jobs: runs-on: ubuntu-latest if: needs.setup.outputs.release_run steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v5 with: pattern: "*-installer" - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v5 with: pattern: "*-metadata" + - uses: actions/download-artifact@v5 + with: + name: "Linux-app" + - name: Rename metadata run: | cp Windows-metadata/autobuild-package.xml Windows-autobuild-package.xml cp Windows-metadata/newview/viewer_version.txt Windows-viewer_version.txt cp macOS-metadata/autobuild-package.xml macOS-autobuild-package.xml cp macOS-metadata/newview/viewer_version.txt macOS-viewer_version.txt + cp Linux-metadata/autobuild-package.xml Linux-autobuild-package.xml + cp Linux-metadata/newview/viewer_version.txt Linux-viewer_version.txt # forked from softprops/action-gh-release - name: Create GitHub release @@ -462,6 +497,7 @@ jobs: files: | macOS-installer/*.dmg Windows-installer/*.exe + *.tar.xz *-autobuild-package.xml *-viewer_version.txt diff --git a/.gitignore b/.gitignore index c4accf37b5b..a784d6e7d4c 100755 --- a/.gitignore +++ b/.gitignore @@ -17,11 +17,11 @@ *~ # Specific paths and/or names +.venv CMakeCache.txt cmake_install.cmake LICENSES -build-darwin-* -build-linux-* +build-* debian/files debian/secondlife-appearance-utility* debian/secondlife-viewer* diff --git a/autobuild.xml b/autobuild.xml index 8a022cd304b..9142cdcea32 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -7,33 +7,65 @@ autobuild installables - SDL + SDL3 platforms + windows64 + + archive + + hash + 121b209bbf8ffb2f7f668a74de0e654f4be7339f + hash_algorithm + sha1 + url + https://github.com/secondlife/3p-sdl3/releases/download/v3.2.24-r1/SDL3-3.2.24-r1-windows64-18539840462.tar.zst + + name + windows64 + linux64 archive hash - 7ea2df03bfc35c06acf23dd9e734adac + 06226c54c57afd601707c0f5f7a2e0736ab1f326 + hash_algorithm + sha1 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1103/2554/SDL-1.2.15-linux64-501092.tar.bz2 + https://github.com/secondlife/3p-sdl3/releases/download/v3.2.24-r1/SDL3-3.2.24-r1-linux64-18539840462.tar.zst name linux64 + darwin64 + + archive + + hash + aff68fb5655629c698e198af1581835267588f77 + hash_algorithm + sha1 + url + https://github.com/secondlife/3p-sdl3/releases/download/v3.2.24-r1/SDL3-3.2.24-r1-darwin64-18539840462.tar.zst + + name + darwin64 + license lgpl license_file - LICENSES/SDL.txt + LICENSES/SDL3.txt copyright - Copyright (C) 1997-2012 Sam Lantinga + Copyright (C) 1997-2022 Sam Lantinga (slouken@libsdl.org) version - 1.2.15 + 3.2.24-r1 + use_scm_version + true name - SDL + SDL3 description Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer. @@ -270,11 +302,11 @@ archive hash - d5fb3832a338bbe4891b823c64fdb4806706568e + e21e7755fe740d5ed30bd29441170449a57caa8b hash_algorithm sha1 url - https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-d7afe27/cubemaptoequirectangular-1.1.0-darwin64-d7afe27.tar.zst + https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-cb8785a/cubemaptoequirectangular-1.1.0-darwin64-cb8785a.tar.zst name darwin64 @@ -284,11 +316,11 @@ archive hash - 77c53daf558f51aec6e9f4bd9e930a103630ee7d + aea0bed0f953a9371b9091f09230b41597f891f7 hash_algorithm sha1 url - https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-d7afe27/cubemaptoequirectangular-1.1.0-linux64-d7afe27.tar.zst + https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-cb8785a/cubemaptoequirectangular-1.1.0-linux64-cb8785a.tar.zst name linux64 @@ -298,11 +330,11 @@ archive hash - 6c51855bcf3a8628289881fdaea08c25cf7b1b90 + eabc3b0c9d9084f49b8a4dc5d3834d77f668c27a hash_algorithm sha1 url - https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-d7afe27/cubemaptoequirectangular-1.1.0-windows64-d7afe27.tar.zst + https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-cb8785a/cubemaptoequirectangular-1.1.0-windows64-cb8785a.tar.zst name windows64 @@ -379,36 +411,6 @@ description Library for transferring data specified with URL syntax - dbus_glib - - platforms - - linux64 - - archive - - hash - 7ee7b9aed3c0c8c09e7bf26bba7af8e1 - url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-dbus-glib/rev/314266/arch/Linux/installer/dbus_glib-0.76-linux64-314266.tar.bz2 - - name - linux64 - - - license - Academic Free License v. 2.1 - license_file - LICENSES/dbus-glib.txt - copyright - Copyright (C) Red Hat Inc. - version - 0.76 - name - dbus_glib - description - D-Bus bindings for glib - dictionaries platforms @@ -450,11 +452,11 @@ archive hash - d44256458ff0ef4db4c91e8e8cc83e8f98b4f1b8 + 2c81fa7aa03b427088ab54ce3b71088a0003126b hash_algorithm sha1 url - https://github.com/secondlife/dullahan/releases/download/v1.21.0-CEF_139.0.28/dullahan-1.21.0.202508272158_139.0.28_g55ab8a8_chromium-139.0.7258.139-darwin64-17279703032.tar.zst + https://github.com/secondlife/dullahan/releases/download/v1.26.0-CEF_139.0.40/dullahan-1.26.0.202510161627_139.0.40_g465474a_chromium-139.0.7258.139-darwin64-18568015445.tar.zst name darwin64 @@ -464,11 +466,11 @@ archive hash - 209d031ae67bc66d8e8f8509c71d259014c65ceb + 8e06d060729250c5bfcb993c8f818f36ea17de16 hash_algorithm sha1 url - https://github.com/secondlife/dullahan/releases/download/v1.14.0-r3/dullahan-1.14.0.202408091637_118.4.1_g3dd6078_chromium-118.0.5993.54-linux64-10322607516.tar.zst + https://github.com/secondlife/dullahan/releases/download/v1.26.0-CEF_139.0.40/dullahan-1.26.0.202510161627_139.0.40_g465474a_chromium-139.0.7258.139-linux64-18568015445.tar.zst name linux64 @@ -478,11 +480,11 @@ archive hash - 9d5af766a87052808e4062978504e9af124fb558 + 7ca6db37f019b47e230c0861607c546d45535367 hash_algorithm sha1 url - https://github.com/secondlife/dullahan/releases/download/v1.21.0-CEF_139.0.28/dullahan-1.21.0.202508272159_139.0.28_g55ab8a8_chromium-139.0.7258.139-windows64-17279703032.tar.zst + https://github.com/secondlife/dullahan/releases/download/v1.26.0-CEF_139.0.40/dullahan-1.26.0.202510161628_139.0.40_g465474a_chromium-139.0.7258.139-windows64-18568015445.tar.zst name windows64 @@ -495,7 +497,7 @@ copyright Copyright (c) 2017, Linden Research, Inc. version - 1.21.0.202508272158_139.0.28_g55ab8a8_chromium-139.0.7258.139 + 1.26.0.202510161627_139.0.40_g465474a_chromium-139.0.7258.139 name dullahan description @@ -595,36 +597,6 @@ description Expat is an XML parser library written in C - fontconfig - - platforms - - linux64 - - archive - - hash - e2419d56960c160670051fbb055fb729 - url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-fontconfig/rev/314281/arch/Linux/installer/fontconfig-2.11.0-linux64-314281.tar.bz2 - - name - linux64 - - - license - bsd - license_file - LICENSES/fontconfig.txt - copyright - Copyright (C) 2000,2001,2002,2003,2004,2006,2007 Keith Packard, 2005 Patrick Lam, 2009 Roozbeh Pournader, 2008,2009 Red Hat, Inc., 2008 Danilo Šegan, 2012 Google, Inc. - version - 2.11.0 - name - fontconfig - description - Fontconfig is a library for configuring and customizing font access. - freetype platforms @@ -791,62 +763,6 @@ source_type git - gstreamer - - platforms - - linux64 - - archive - - hash - 7c9d7cc88add7831a6afeedc20cad2fe - url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-gstreamer/rev/314267/arch/Linux/installer/gstreamer-0.10.6.314267-linux64-314267.tar.bz2 - - name - linux64 - - - license - LGPL - license_file - LICENSES/gstreamer.txt - copyright - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - version - 0.10.6.314267 - name - gstreamer - - gtk-atk-pango-glib - - platforms - - linux64 - - archive - - hash - de7bba8fd2275a11b077b124413065d0 - url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-gtk-atk-pango-glib/rev/314220/arch/Linux/installer/gtk_atk_pango_glib-0.1-linux64-314220.tar.bz2 - - name - linux64 - - - license - lgpl - license_file - LICENSES/gtk-atk-pango-glib.txt - copyright - Copyright (various, see sources) - version - 0.1 - name - gtk-atk-pango-glib - havok-source platforms @@ -1277,36 +1193,6 @@ description PNG Reference library - libuuid - - platforms - - linux64 - - archive - - hash - fb89f1281dd54d8b99b339fc5b712b27 - url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-libuuid/rev/314269/arch/Linux/installer/libuuid-1.6.2-linux64-314269.tar.bz2 - - name - linux64 - - - license - UUID - license_file - LICENSES/uuid.txt - copyright - Copyright (c) 2004-2008 The OSSP Project <http://www.ossp.org/> - version - 1.6.2 - name - libuuid - description - OSSP uuid is a ISO-C:1999 application programming interface (API) and corresponding command line interface (CLI) for the generation of DCE 1.1, ISO/IEC 11578:1996 and RFC 4122 compliant Universally Unique Identifier (UUID). - libxml2 platforms @@ -1367,36 +1253,6 @@ description Libxml2 is the XML C parser and toolkit developed for the Gnome project. - llappearance_utility - - platforms - - linux - - archive - - hash - fddd634dec5ec03924d62cc774f7f8ea - url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/p64_viewer-llappearance-utility/rev/317266/arch/Linux/installer/llappearance_utility-0.0.1-linux-317266.tar.bz2 - - name - linux - - - license - Proprietary - license_file - LICENSES/llappearanceutility.txt - copyright - Copyright (c) 2000-2012, Linden Research, Inc. - version - 0.0.1 - name - llappearance_utility - description - Linden Lab appearance utility for server-side avatar baking services. - llca platforms @@ -1574,32 +1430,6 @@ name llphysicsextensions_tpv - mesa - - platforms - - linux - - archive - - hash - 22c50a5d362cad311b4f413cfcffbba2 - url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/mesa_3p-update-mesa/rev/297294/arch/Linux/installer/mesa-7.11.1.297294-linux-297294.tar.bz2 - - name - linux - - - license - mesa - license_file - LICENSES/mesa.txt - version - 7.11.1.297294 - name - mesa - meshoptimizer platforms @@ -1999,6 +1829,23 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors open-libndofdev + platforms + + linux64 + + archive + + hash + 795d1e60f3e1e9092788214a6750e6506391cac5 + hash_algorithm + sha1 + url + https://github.com/secondlife/3p-open-libndofdev/releases/download/v1.14-r6/open_libndofdev-0.14.18543500856-linux64-18543500856.tar.zst + + name + linux64 + + license BSD license_file @@ -2006,7 +1853,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors copyright Copyright (c) 2008, Jan Ciger (jan.ciger (at) gmail.com) version - 0.14.11968684513 + 0.14.18543500856 name open-libndofdev description @@ -2604,7 +2451,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors description Linden Lab Viewer Management Process suite. source - https://bitbucket.org/lindenlab/vmp-standalone + https://github.com/secondlife/viewer-manager source_type hg @@ -2695,11 +2542,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 43c5f93517794aeade550e4266b959d1f0cfcb7f + a5e72a9d13b6c4646d1e02b5820f16560d204de7 hash_algorithm sha1 url - https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-darwin64-17630578914.tar.zst + https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.21/webrtc-m137.7151.04.21.18609120431-darwin64-18609120431.tar.zst name darwin64 @@ -2709,11 +2556,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - efc5b176d878cfc16b8f82445d82ddb96815b6ab + 1030e5086f401d738463223da3ed99c225340f39 hash_algorithm sha1 url - https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-linux64-17630578914.tar.zst + https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.21/webrtc-m137.7151.04.21.18609120431-linux64-18609120431.tar.zst name linux64 @@ -2723,11 +2570,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 1e36f100de32c7c71325497a672fb1659b3f206d + d1cae9bc8866ca01aa9f5e72b36d12ef608b1998 hash_algorithm sha1 url - https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-windows64-17630578914.tar.zst + https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.21/webrtc-m137.7151.04.21.18609120431-windows64-18609120431.tar.zst name windows64 @@ -2740,7 +2587,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors copyright Copyright (c) 2011, The WebRTC project authors. All rights reserved. version - m137.7151.04.20-universal.17630578914 + m137.7151.04.21.18609120431 name webrtc vcs_branch @@ -2953,11 +2800,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 140d8fc952a10edb5f2d72ab405336019ef32cadfa64f0cfce76c9de4bc6268cbc87cc8cd89d3417fb78b531d441701afc8d016bafe4bd275df2707f7daf1387 + 49046b0b41310d2fb0d72853730b2faad35d3e36 hash_algorithm - blake2b + sha1 url - https://github.com/AlchemyViewer/3p-vhacd/releases/download/v4.1.0-r2/vhacd-4.1.0-r2-common-18166921729.tar.zst + https://github.com/secondlife/3p-vhacd/releases/download/v4.1.0-r1/vhacd-4.1.0-r1-common-18475951995.tar.zst name common @@ -2970,7 +2817,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors copyright Copyright (c) 2011, Khaled Mamou version - 4.1.0-r2 + 4.1.0-r1 name vhacd description @@ -3213,7 +3060,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors -G Ninja - -DLL_TESTS=Off arguments @@ -3223,7 +3069,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors build command - ninja + cmake + options + + --build + . + --config + Release + --parallel + $AUTOBUILD_CPU_COUNT + default True @@ -3238,25 +3093,25 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors -G Ninja - -DLL_TESTS=Off build command - ninja + cmake + options + + --build + . + --config + Release + --parallel + $AUTOBUILD_CPU_COUNT + name ReleaseOS - default - - build - - - name - default - build_directory build-linux-x86_64 diff --git a/build.sh b/build.sh index edd18bbad61..7654e78eaf1 100755 --- a/build.sh +++ b/build.sh @@ -45,7 +45,7 @@ build_dir_Darwin() build_dir_Linux() { - echo build-linux-i686 + echo build-linux-x86_64 } build_dir_CYGWIN() @@ -164,6 +164,24 @@ pre_build() fi fi + if [[ "$arch" == "Linux" ]] + then + HAVOK=OFF + + # RELEASE_CRASH_REPORTING is tuned on unconditionaly, this is fine but not for Linux as of now (due to missing breakpad/crashpad support) + RELEASE_CRASH_REPORTING=OFF + + # Builds turn on HAVOK even when config is ReleaseOS. + # This needs AUTOBUILD_GITHUB_TOKEN to be set in the environment. But this is not set for PRs apparently. + # Still this seemlingy works on Windows and Mac, why not on the Linux runner? Mystery to be solved elsewhere. + + + if [[ "$variant" == "ReleaseOS" ]] + then + HAVOK=OFF + fi + fi + if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ] then case "$arch" in diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 246bd7bfa0b..4572dd0159a 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -104,17 +104,7 @@ if (ENABLE_MEDIA_PLUGINS) add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins) endif (ENABLE_MEDIA_PLUGINS) -if (LINUX) - if (INSTALL_PROPRIETARY) - include(LLAppearanceUtility) - add_subdirectory(${LLAPPEARANCEUTILITY_SRC_DIR} ${LLAPPEARANCEUTILITY_BIN_DIR}) - endif (INSTALL_PROPRIETARY) -elseif (WINDOWS) - # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake - if (EXISTS ${VIEWER_DIR}win_setup) - add_subdirectory(${VIEWER_DIR}win_setup) - endif (EXISTS ${VIEWER_DIR}win_setup) -endif (LINUX) +add_subdirectory(llappearanceutility) if (WINDOWS) # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake diff --git a/indra/cmake/00-COMPILE-LINK-RUN.txt b/indra/cmake/00-COMPILE-LINK-RUN.txt index 1933072a6d3..7b91b5a0d4c 100644 --- a/indra/cmake/00-COMPILE-LINK-RUN.txt +++ b/indra/cmake/00-COMPILE-LINK-RUN.txt @@ -117,7 +117,7 @@ Compilation currently being generated with a link path of '@executable_path/../Resources/'. If we were to follow the recommendations in dyld's man page, we’d instead reference - '@loader_path/', use -rpath on the executable link + '@loader_path/', use -rpath on the executable link (pointing to the 'Resources' subdir of the main executable), and be able to avoid some symlinking in the .app tree. @@ -162,7 +162,7 @@ Linking * Update the autobuild.xml of ALL consumers of the library. In the case of zlib, that meant updating freetype, libpng, openssl, - libxml2, fontconfig, curl, Boost, SDL, llqtwebkit, google-mock and + libxml2, fontconfig, curl, Boost, SDL3, llqtwebkit, google-mock and colladadom. * Confirm by test and observation that the consumers actually use diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 99ea22ab4b6..ee7f6a2731b 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -11,13 +11,20 @@ # # Also realize that CMAKE_CXX_FLAGS may already be partially populated on # entry to this file. +# +# Additionally CMAKE_C_FLAGS is prepended to CMAKE_CXX_FLAGS_RELEASE and +# CMAKE_CXX_FLAGS_RELWITHDEBINFO which risks having flags overriden by cmake +# inserting additional options that are part of the build config type. #***************************************************************************** include_guard() include(Variables) +include(Linking) # We go to some trouble to set LL_BUILD to the set of relevant compiler flags. -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} $ENV{LL_BUILD}") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} $ENV{LL_BUILD_RELEASE}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} $ENV{LL_BUILD_RELWITHDEBINFO}") + # Given that, all the flags you see added below are flags NOT present in # https://bitbucket.org/lindenlab/viewer-build-variables/src/tip/variables. # Before adding new ones here, it's important to ask: can this flag really be @@ -111,7 +118,7 @@ if (WINDOWS) #ND: When using something like buildcache (https://github.com/mbitsnbites/buildcache) # to make those wrappers work /Zi must be changed to /Z7, as /Zi due to it's nature is not compatible with caching - if(${CMAKE_CXX_COMPILER_LAUNCHER} MATCHES ".*cache.*") + if (${CMAKE_CXX_COMPILER_LAUNCHER} MATCHES ".*cache.*") add_compile_options( /Z7 ) string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") @@ -125,9 +132,6 @@ endif (WINDOWS) if (LINUX) set(CMAKE_SKIP_RPATH TRUE) - # EXTERNAL_TOS - # force this platform to accept TOS via external browser - # LL_IGNORE_SIGCHLD # don't catch SIGCHLD in our base application class for the viewer - some of # our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The @@ -135,42 +139,44 @@ if (LINUX) add_compile_definitions( _REENTRANT - _FORTIFY_SOURCE=2 - EXTERNAL_TOS APPID=secondlife LL_IGNORE_SIGCHLD ) + + if( ENABLE_ASAN ) + add_compile_options(-U_FORTIFY_SOURCE + -fsanitize=address + --param asan-stack=0 + ) + add_link_options(-fsanitize=address) + else() + add_compile_definitions( $<$,$>:_FORTIFY_SOURCE=2> ) + endif() + add_compile_options( + $<$,$>:-fstack-protector> -fexceptions -fno-math-errno -fno-strict-aliasing -fsigned-char + -g -msse2 - -mfpmath=sse -pthread - -Wno-parentheses - -Wno-deprecated -fvisibility=hidden ) - if (ADDRESS_SIZE EQUAL 32) - add_compile_options(-march=pentium4) - endif (ADDRESS_SIZE EQUAL 32) - - # this stops us requiring a really recent glibc at runtime - add_compile_options(-fno-stack-protector) - # linking can be very memory-hungry, especially the final viewer link - set(CMAKE_CXX_LINK_FLAGS "-Wl,--no-keep-memory") - - set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG}") + add_link_options( + "LINKER:-z,relro" + "LINKER:-z,now" + "LINKER:--build-id" + "LINKER:--as-needed" + ) endif (LINUX) if (DARWIN) # Use rpath loading on macos set(CMAKE_MACOSX_RPATH TRUE) - # Warnings should be fatal -- thanks, Nicky Perian, for spotting reversed default - set(CLANG_DISABLE_FATAL_WARNINGS OFF) set(CMAKE_CXX_LINK_FLAGS "-Wl,-headerpad_max_install_names,-search_paths_first") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_LINK_FLAGS}") @@ -191,7 +197,7 @@ if (LINUX OR DARWIN) endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - add_compile_options(-Wno-stringop-truncation -Wno-parentheses -Wno-maybe-uninitialized) + add_compile_options(-Wno-stringop-truncation -Wno-stringop-overflow -Wno-parentheses -Wno-maybe-uninitialized) endif() if (NOT GCC_DISABLE_FATAL_WARNINGS AND NOT CLANG_DISABLE_FATAL_WARNINGS) diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index b57c33c3e00..610a4f62326 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -1,5 +1,6 @@ # -*- cmake -*- include(Prebuilt) +include(Linking) include_guard() @@ -16,107 +17,69 @@ use_prebuilt_binary(boost) # with the address size. set(addrsfx "-x${ADDRESS_SIZE}") -if (WINDOWS) - - find_library(BOOST_CONTEXT_LIBRARY - NAMES - libboost_context-mt - libboost_context-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_FIBER_LIBRARY - NAMES - libboost_fiber-mt - libboost_fiber-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_FILESYSTEM_LIBRARY - NAMES - libboost_filesystem-mt - libboost_filesystem-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_PROGRAMOPTIONS_LIBRARY - NAMES - libboost_program_options-mt - libboost_program_options-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_REGEX_LIBRARY - NAMES - libboost_regex-mt - libboost_regex-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_SYSTEM_LIBRARY - NAMES - libboost_system-mt - libboost_system-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_THREAD_LIBRARY - NAMES - libboost_thread-mt - libboost_thread-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_URL_LIBRARY - NAMES - libboost_url-mt - libboost_url-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -else (WINDOWS) - - find_library(BOOST_CONTEXT_LIBRARY - NAMES - boost_context-mt - boost_context-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_FIBER_LIBRARY - NAMES - boost_fiber-mt - boost_fiber-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_FILESYSTEM_LIBRARY - NAMES - boost_filesystem-mt - boost_filesystem-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_PROGRAMOPTIONS_LIBRARY - NAMES - boost_program_options-mt - boost_program_options-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_REGEX_LIBRARY - NAMES - boost_regex-mt - boost_regex-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_SYSTEM_LIBRARY - NAMES - boost_system-mt - boost_system-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_THREAD_LIBRARY - NAMES - boost_thread-mt - boost_thread-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(BOOST_URL_LIBRARY - NAMES - boost_url-mt - boost_url-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -endif (WINDOWS) +find_library(BOOST_CONTEXT_LIBRARY + NAMES + libboost_context-mt + libboost_context-mt${addrsfx} + boost_context-mt + boost_context-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + +find_library(BOOST_FIBER_LIBRARY + NAMES + libboost_fiber-mt + libboost_fiber-mt${addrsfx} + boost_fiber-mt + boost_fiber-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + +find_library(BOOST_FILESYSTEM_LIBRARY + NAMES + libboost_filesystem-mt + libboost_filesystem-mt${addrsfx} + boost_filesystem-mt + boost_filesystem-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + +find_library(BOOST_PROGRAMOPTIONS_LIBRARY + NAMES + libboost_program_options-mt + libboost_program_options-mt${addrsfx} + boost_program_options-mt + boost_program_options-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + +find_library(BOOST_REGEX_LIBRARY + NAMES + libboost_regex-mt + libboost_regex-mt${addrsfx} + boost_regex-mt + boost_regex-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + +find_library(BOOST_SYSTEM_LIBRARY + NAMES + libboost_system-mt + libboost_system-mt${addrsfx} + boost_system-mt + boost_system-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + +find_library(BOOST_THREAD_LIBRARY + NAMES + libboost_thread-mt + libboost_thread-mt${addrsfx} + boost_thread-mt + boost_thread-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + +find_library(BOOST_URL_LIBRARY + NAMES + libboost_url-mt + libboost_url-mt${addrsfx} + boost_url-mt + boost_url-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) target_link_libraries(ll::boost INTERFACE ${BOOST_FIBER_LIBRARY} diff --git a/indra/cmake/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake index e27929fa088..5f5c55f0e95 100644 --- a/indra/cmake/CEFPlugin.cmake +++ b/indra/cmake/CEFPlugin.cmake @@ -10,9 +10,9 @@ target_include_directories( ll::cef SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/inclu if (WINDOWS) target_link_libraries( ll::cef INTERFACE - libcef.lib - libcef_dll_wrapper.lib - dullahan.lib + ${ARCH_PREBUILT_DIRS_RELEASE}/libcef.lib + ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.lib + ${ARCH_PREBUILT_DIRS_RELEASE}/dullahan.lib ) elseif (DARWIN) FIND_LIBRARY(APPKIT_LIBRARY AppKit) @@ -32,4 +32,9 @@ elseif (DARWIN) ) elseif (LINUX) + target_link_libraries( ll::cef INTERFACE + ${ARCH_PREBUILT_DIRS_RELEASE}/libdullahan.a + ${ARCH_PREBUILT_DIRS_RELEASE}/libcef.so + ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a + ) endif (WINDOWS) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 2ba282bdb78..58475539934 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -11,23 +11,25 @@ set(cmake_SOURCE_FILES Audio.cmake Boost.cmake bugsplat.cmake + BuildPackagesInfo.cmake BuildVersion.cmake CEFPlugin.cmake CEFPlugin.cmake CMakeCopyIfDifferent.cmake - ConfigurePkgConfig.cmake - CURL.cmake Copy3rdPartyLibs.cmake - DBusGlib.cmake + CURL.cmake DeploySharedLibs.cmake Discord.cmake DragDrop.cmake EXPAT.cmake FindAutobuild.cmake + FindPipeWire.cmake FreeType.cmake GLEXT.cmake GLH.cmake + GLIB.cmake GLM.cmake + GStreamer10Plugin.cmake Havok.cmake Hunspell.cmake LLAddBuildTest.cmake @@ -53,6 +55,7 @@ set(cmake_SOURCE_FILES Prebuilt.cmake PulseAudio.cmake Python.cmake + SDL3.cmake SSE2NEON.cmake TemplateCheck.cmake TinyEXR.cmake diff --git a/indra/cmake/ConfigurePkgConfig.cmake b/indra/cmake/ConfigurePkgConfig.cmake deleted file mode 100644 index 9e798d663b5..00000000000 --- a/indra/cmake/ConfigurePkgConfig.cmake +++ /dev/null @@ -1,74 +0,0 @@ -# -*- cmake -*- - -SET(DEBUG_PKG_CONFIG "YES") - -# Don't change this if manually set by user. -IF("$ENV{PKG_CONFIG_LIBDIR}" STREQUAL "") - - # Guess at architecture-specific system library paths. - if (ADDRESS_SIZE EQUAL 32) - SET(PKG_CONFIG_NO_MULTI_GUESS /usr/lib32 /usr/lib) - SET(PKG_CONFIG_NO_MULTI_LOCAL_GUESS /usr/local/lib32 /usr/local/lib) - SET(PKG_CONFIG_MULTI_GUESS /usr/lib/i386-linux-gnu) - SET(PKG_CONFIG_MULTI_LOCAL_GUESS /usr/local/lib/i386-linux-gnu) - else (ADDRESS_SIZE EQUAL 32) - SET(PKG_CONFIG_NO_MULTI_GUESS /usr/lib64 /usr/lib) - SET(PKG_CONFIG_NO_MULTI_LOCAL_GUESS /usr/local/lib64 /usr/local/lib) - SET(PKG_CONFIG_MULTI_GUESS /usr/local/lib/x86_64-linux-gnu) - SET(PKG_CONFIG_MULTI_LOCAL_GUESS /usr/local/lib/x86_64-linux-gnu) - endif (ADDRESS_SIZE EQUAL 32) - - # Use DPKG architecture, if available. - IF (${DPKG_ARCH}) - SET(PKG_CONFIG_MULTI_GUESS /usr/lib/${DPKG_ARCH}) - SET(PKG_CONFIG_MULTI_LOCAL_GUESS /usrlocal/lib/${DPKG_ARCH}) - ENDIF (${DPKG_ARCH}) - - # Explicitly include anything listed in PKG_CONFIG_PATH - string(REPLACE ":" ";" PKG_CONFIG_PATH_LIST "$ENV{PKG_CONFIG_PATH}") - FOREACH(PKG_CONFIG_DIR ${PKG_CONFIG_PATH_LIST}) - SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_DIR}/pkgconfig") - ENDFOREACH(PKG_CONFIG_DIR) - - # Look for valid pkgconfig directories. - FIND_PATH(PKG_CONFIG_ENV pkgconfig ENV LD_LIBRARY_PATH) - FIND_PATH(PKG_CONFIG_MULTI pkgconfig HINT ${PKG_CONFIG_MULTI_GUESS}) - FIND_PATH(PKG_CONFIG_MULTI_LOCAL pkgconfig HINT ${PKG_CONFIG_MULTI_LOCAL_GUESS}) - FIND_PATH(PKG_CONFIG_NO_MULTI pkgconfig HINT ${PKG_CONFIG_NO_MULTI_GUESS}) - FIND_PATH(PKG_CONFIG_NO_MULTI_LOCAL pkgconfig HINT ${PKG_CONFIG_NO_MULTI_LOCAL_GUESS}) - - # Add anything we found to our list. - IF(NOT PKG_CONFIG_ENV STREQUAL PKG_CONFIG_ENV-NOTFOUND) - SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_ENV}/pkgconfig") - ENDIF(NOT PKG_CONFIG_ENV STREQUAL PKG_CONFIG_ENV-NOTFOUND) - - IF(NOT PKG_CONFIG_MULTI STREQUAL PKG_CONFIG_MULTI-NOTFOUND) - SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_MULTI}/pkgconfig") - ENDIF(NOT PKG_CONFIG_MULTI STREQUAL PKG_CONFIG_MULTI-NOTFOUND) - - IF(NOT PKG_CONFIG_MULTI_LOCAL STREQUAL PKG_CONFIG_MULTI_LOCAL-NOTFOUND) - SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_MULTI_LOCAL}/pkgconfig") - ENDIF(NOT PKG_CONFIG_MULTI_LOCAL STREQUAL PKG_CONFIG_MULTI_LOCAL-NOTFOUND) - - IF(NOT PKG_CONFIG_NO_MULTI STREQUAL PKG_CONFIG_NO_MULTI-NOTFOUND) - SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_NO_MULTI}/pkgconfig") - ENDIF(NOT PKG_CONFIG_NO_MULTI STREQUAL PKG_CONFIG_NO_MULTI-NOTFOUND) - - IF(NOT PKG_CONFIG_NO_MULTI_LOCAL STREQUAL PKG_CONFIG_NO_MULTI_LOCAL-NOTFOUND) - SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_NO_MULTI_LOCAL}/pkgconfig") - ENDIF(NOT PKG_CONFIG_NO_MULTI_LOCAL STREQUAL PKG_CONFIG_NO_MULTI_LOCAL-NOTFOUND) - - # Also add some non-architecture specific package locations. - SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:/usr/share/pkgconfig:/usr/local/share/pkgconfig") - - # Remove first unwanted ':' - string(SUBSTRING ${VALID_PKG_LIBDIRS} 1 -1 VALID_PKG_LIBDIRS) - - # Set PKG_CONFIG_LIBDIR environment. - SET(ENV{PKG_CONFIG_LIBDIR} ${VALID_PKG_LIBDIRS}) -ENDIF("$ENV{PKG_CONFIG_LIBDIR}" STREQUAL "") - -IF(DEBUG_PKG_CONFIG) - MESSAGE(STATUS "Using PKG_CONFIG_LIBDIR=$ENV{PKG_CONFIG_LIBDIR}") -ENDIF(DEBUG_PKG_CONFIG) - diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 680f2f3ac20..9760dc653c8 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -211,17 +211,10 @@ elseif(LINUX) if( USE_AUTOBUILD_3P ) list( APPEND release_files - libatk-1.0.so - libfreetype.so.6.6.2 - libfreetype.so.6 - libopenjp2.so - libuuid.so.16 - libuuid.so.16.0.22 - libfontconfig.so.1.8.0 - libfontconfig.so.1 - libgmodule-2.0.so - libgobject-2.0.so - ) + libSDL3.so + libSDL3.so.0 + libSDL3.so.0.2.24 + ) endif() else(WINDOWS) diff --git a/indra/cmake/DBusGlib.cmake b/indra/cmake/DBusGlib.cmake deleted file mode 100644 index c9b727ca9df..00000000000 --- a/indra/cmake/DBusGlib.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -add_library( ll::dbus INTERFACE IMPORTED) - -if( LINUX ) - # Only define this when not using the prebuild 3ps, lls prebuild is broken - if( NOT USE_AUTOBUILD_3P ) - target_compile_definitions( ll::dbus INTERFACE LL_DBUS_ENABLED ) - endif() - use_system_binary(dbus) - - use_prebuilt_binary(dbus_glib) -endif() diff --git a/indra/cmake/Discord.cmake b/indra/cmake/Discord.cmake index 95cfaacf5b4..0e63d053500 100644 --- a/indra/cmake/Discord.cmake +++ b/indra/cmake/Discord.cmake @@ -2,10 +2,23 @@ include(Prebuilt) include_guard() -add_library(ll::discord_sdk INTERFACE IMPORTED) -target_compile_definitions(ll::discord_sdk INTERFACE LL_DISCORD=1) +option(USE_DISCORD "Enable Discord SDK" OFF) -use_prebuilt_binary(discord_sdk) +if(USE_DISCORD) + add_library(ll::discord_sdk INTERFACE IMPORTED) -target_include_directories(ll::discord_sdk SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/discord_sdk) -target_link_libraries(ll::discord_sdk INTERFACE discord_partner_sdk) + target_compile_definitions(ll::discord_sdk INTERFACE LL_DISCORD=1) + + use_prebuilt_binary(discord_sdk) + + find_library(DISCORD_SDK_LIBRARY + NAMES + discord_partner_sdk + discord_partner_sdk.lib + libdiscord_partner_sdk.so + libdiscord_partner_sdk.dylib + PATHS "${ARCH_PREBUILT_DIRS_ARCH_RELEASE}" "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + target_include_directories(ll::discord_sdk SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/discord_sdk) + target_link_libraries(ll::discord_sdk INTERFACE ${DISCORD_SDK_LIBRARY}) +endif() diff --git a/indra/cmake/FindPipeWire.cmake b/indra/cmake/FindPipeWire.cmake new file mode 100644 index 00000000000..868acf5ec15 --- /dev/null +++ b/indra/cmake/FindPipeWire.cmake @@ -0,0 +1,100 @@ +# cmake-format: off +# .rst: FindPipeWire +# ------- +# +# Try to find PipeWire on a Unix system. +# +# This will define the following variables: +# +# ``PIPEWIRE_FOUND`` True if (the requested version of) PipeWire is available +# ``PIPEWIRE_VERSION`` The version of PipeWire ``PIPEWIRE_LIBRARIES`` This can +# be passed to target_link_libraries() instead of the ``PipeWire::PipeWire`` +# target ``PIPEWIRE_INCLUDE_DIRS`` This should be passed to +# target_include_directories() if the target is not used for linking +# ``PIPEWIRE_COMPILE_FLAGS`` This should be passed to target_compile_options() +# if the target is not used for linking +# +# If ``PIPEWIRE_FOUND`` is TRUE, it will also define the following imported +# target: +# +# ``PipeWire::PipeWire`` The PipeWire library +# +# In general we recommend using the imported target, as it is easier to use. +# Bear in mind, however, that if the target is in the link interface of an +# exported library, it must be made available by the package config file. + +# ============================================================================= +# Copyright 2014 Alex Merry Copyright 2014 Martin Gräßlin +# Copyright 2018-2020 Jan Grulich +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the copyright notice, this list +# of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# ============================================================================= +# cmake-format: on + +# Use pkg-config to get the directories and then use these values in the FIND_PATH() and FIND_LIBRARY() calls +find_package(PkgConfig QUIET) + +pkg_search_module(PKG_PIPEWIRE QUIET libpipewire-0.3) +pkg_search_module(PKG_SPA QUIET libspa-0.2) + +set(PIPEWIRE_COMPILE_FLAGS "${PKG_PIPEWIRE_CFLAGS}" "${PKG_SPA_CFLAGS}") +set(PIPEWIRE_VERSION "${PKG_PIPEWIRE_VERSION}") + +find_path( + PIPEWIRE_INCLUDE_DIRS + NAMES pipewire/pipewire.h + HINTS ${PKG_PIPEWIRE_INCLUDE_DIRS} ${PKG_PIPEWIRE_INCLUDE_DIRS}/pipewire-0.3) + +find_path( + SPA_INCLUDE_DIRS + NAMES spa/param/props.h + HINTS ${PKG_SPA_INCLUDE_DIRS} ${PKG_SPA_INCLUDE_DIRS}/spa-0.2) + +find_library( + PIPEWIRE_LIBRARIES + NAMES pipewire-0.3 + HINTS ${PKG_PIPEWIRE_LIBRARY_DIRS}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + PipeWire + FOUND_VAR PIPEWIRE_FOUND + REQUIRED_VARS PIPEWIRE_LIBRARIES PIPEWIRE_INCLUDE_DIRS SPA_INCLUDE_DIRS + VERSION_VAR PIPEWIRE_VERSION) + +if(PIPEWIRE_FOUND AND NOT TARGET PipeWire::PipeWire) + add_library(PipeWire::PipeWire UNKNOWN IMPORTED) + set_target_properties( + PipeWire::PipeWire + PROPERTIES IMPORTED_LOCATION "${PIPEWIRE_LIBRARIES}" + INTERFACE_COMPILE_OPTIONS "${PIPEWIRE_COMPILE_FLAGS}" + INTERFACE_INCLUDE_DIRECTORIES "${PIPEWIRE_INCLUDE_DIRS};${SPA_INCLUDE_DIRS}") +endif() + +mark_as_advanced(PIPEWIRE_LIBRARIES PIPEWIRE_INCLUDE_DIRS) + +include(FeatureSummary) +set_package_properties( + PipeWire PROPERTIES + URL "https://www.pipewire.org" + DESCRIPTION "PipeWire - multimedia processing") diff --git a/indra/cmake/FreeType.cmake b/indra/cmake/FreeType.cmake index 3c635e851b1..eb018c09e99 100644 --- a/indra/cmake/FreeType.cmake +++ b/indra/cmake/FreeType.cmake @@ -1,6 +1,8 @@ # -*- cmake -*- include(Prebuilt) include(Linking) +include(PNG) +include(ZLIBNG) include_guard() add_library( ll::freetype INTERFACE IMPORTED ) @@ -15,4 +17,4 @@ find_library(FREETYPE_LIBRARY libfreetype.a PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) -target_link_libraries(ll::freetype INTERFACE ${FREETYPE_LIBRARY}) +target_link_libraries(ll::freetype INTERFACE ${FREETYPE_LIBRARY} ll::libpng ll::zlib-ng) diff --git a/indra/cmake/GLIB.cmake b/indra/cmake/GLIB.cmake new file mode 100644 index 00000000000..f52cbb7f871 --- /dev/null +++ b/indra/cmake/GLIB.cmake @@ -0,0 +1,22 @@ +include_guard() + +include(Prebuilt) + +add_library( ll::glib INTERFACE IMPORTED ) +add_library( ll::glib_headers INTERFACE IMPORTED ) +add_library( ll::gio INTERFACE IMPORTED ) + +if( LINUX ) + find_package(PkgConfig REQUIRED) + pkg_search_module(GLIB REQUIRED glib-2.0) + pkg_search_module(GIO REQUIRED gio-2.0) + + target_include_directories( ll::glib SYSTEM INTERFACE ${GLIB_INCLUDE_DIRS} ) + target_link_libraries( ll::glib INTERFACE ${GLIB_LDFLAGS} ) + target_compile_definitions( ll::glib INTERFACE -DLL_GLIB=1) + + target_include_directories( ll::glib_headers SYSTEM INTERFACE ${GLIB_INCLUDE_DIRS} ) + target_compile_definitions( ll::glib_headers INTERFACE -DLL_GLIB=1) + + target_link_libraries( ll::gio INTERFACE ${GIO_LDFLAGS} ) +endif() diff --git a/indra/cmake/GStreamer010Plugin.cmake b/indra/cmake/GStreamer010Plugin.cmake deleted file mode 100644 index 61f6f740336..00000000000 --- a/indra/cmake/GStreamer010Plugin.cmake +++ /dev/null @@ -1,12 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) -if (NOT LINUX) - return() -endif() - -add_library( ll::gstreamer INTERFACE IMPORTED ) -target_compile_definitions( ll::gstreamer INTERFACE LL_GSTREAMER010_ENABLED=1) -use_system_binary(gstreamer) - -use_prebuilt_binary(gstreamer) - diff --git a/indra/cmake/GStreamer10Plugin.cmake b/indra/cmake/GStreamer10Plugin.cmake new file mode 100644 index 00000000000..01522db3a38 --- /dev/null +++ b/indra/cmake/GStreamer10Plugin.cmake @@ -0,0 +1,27 @@ +# -*- cmake -*- + +include_guard() + +include(Prebuilt) +include(GLIB) + +add_library( ll::gstreamer10 INTERFACE IMPORTED ) + +if (LINUX) + find_package(PkgConfig REQUIRED) + + pkg_check_modules(GSTREAMER10 REQUIRED gstreamer-1.0) + pkg_check_modules(GSTREAMER10_PLUGINS_BASE REQUIRED gstreamer-plugins-base-1.0) + + target_include_directories( ll::gstreamer10 SYSTEM INTERFACE ${GSTREAMER10_INCLUDE_DIRS}) + target_link_libraries( ll::gstreamer10 INTERFACE ll::glib_headers) + +endif () + +if (GSTREAMER10_FOUND AND GSTREAMER10_PLUGINS_BASE_FOUND) + set(GSTREAMER10 ON CACHE BOOL "Build with GStreamer-1.0 streaming media support.") +endif (GSTREAMER10_FOUND AND GSTREAMER10_PLUGINS_BASE_FOUND) + +if (GSTREAMER10) + add_definitions(-DLL_GSTREAMER10_ENABLED=1) +endif (GSTREAMER10) diff --git a/indra/cmake/JPEG.cmake b/indra/cmake/JPEG.cmake index f864ca7f8d1..49880e7f727 100644 --- a/indra/cmake/JPEG.cmake +++ b/indra/cmake/JPEG.cmake @@ -11,6 +11,9 @@ use_prebuilt_binary(libjpeg-turbo) find_library(JPEG_LIBRARY NAMES + jpeg + jpeg-static + jpeg-static.lib jpeg.lib libjpeg.a PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) diff --git a/indra/cmake/LLAppearanceUtility.cmake b/indra/cmake/LLAppearanceUtility.cmake deleted file mode 100644 index 0eb3c723d5d..00000000000 --- a/indra/cmake/LLAppearanceUtility.cmake +++ /dev/null @@ -1,12 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) -include(Boost) - -# Linux proprietary build only -if (INSTALL_PROPRIETARY) - if(LINUX) - use_prebuilt_binary(llappearance_utility) - set(LLAPPEARANCEUTILITY_SRC_DIR ${LIBS_PREBUILT_DIR}/llappearanceutility/src) - set(LLAPPEARANCEUTILITY_BIN_DIR ${CMAKE_BINARY_DIR}/llappearanceutility) - endif (LINUX) -endif (INSTALL_PROPRIETARY) diff --git a/indra/cmake/LLKDU.cmake b/indra/cmake/LLKDU.cmake index 7680ab7b542..3009b4b9cca 100644 --- a/indra/cmake/LLKDU.cmake +++ b/indra/cmake/LLKDU.cmake @@ -14,19 +14,11 @@ if (USE_KDU) include(Prebuilt) use_prebuilt_binary(kdu) - if (WINDOWS) - find_library(KDU_LIBRARY - NAMES - kdu - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - else (WINDOWS) - find_library(KDU_LIBRARY - NAMES - libkdu.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - endif (WINDOWS) + find_library(KDU_LIBRARY + NAMES + kdu + libkdu.a + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) target_link_libraries(ll::kdu INTERFACE ${KDU_LIBRARY}) diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake index 2e1b601b797..d5840379ac9 100644 --- a/indra/cmake/LLWindow.cmake +++ b/indra/cmake/LLWindow.cmake @@ -3,20 +3,12 @@ include(Variables) include(GLEXT) include(Prebuilt) +include(SDL3) include_guard() -add_library( ll::SDL INTERFACE IMPORTED ) - if (LINUX) - #Must come first as use_system_binary can exit this file early - target_compile_definitions( ll::SDL INTERFACE LL_SDL=1) - - use_system_binary(SDL) - use_prebuilt_binary(SDL) - - target_include_directories( ll::SDL SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) - target_link_libraries( ll::SDL INTERFACE SDL directfb fusion direct X11) + set(USE_SDL_WINDOW ON CACHE BOOL "Build with SDL window backend") +else() + set(USE_SDL_WINDOW OFF CACHE BOOL "Build with SDL window backend") endif (LINUX) - - diff --git a/indra/cmake/LibVLCPlugin.cmake b/indra/cmake/LibVLCPlugin.cmake index 6361028c0c4..a38c660a339 100644 --- a/indra/cmake/LibVLCPlugin.cmake +++ b/indra/cmake/LibVLCPlugin.cmake @@ -5,20 +5,31 @@ include(Prebuilt) include_guard() add_library( ll::libvlc INTERFACE IMPORTED ) -use_prebuilt_binary(vlc-bin) set(LIBVLCPLUGIN ON CACHE BOOL "LIBVLCPLUGIN support for the llplugin/llmedia test apps.") -find_library(VLC_LIBRARY - NAMES - libvlc.lib - libvlc.dylib - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) +if (LIBVLCPLUGIN) + if(LINUX) + find_package(PkgConfig REQUIRED) -find_library(VLCCORE_LIBRARY - NAMES - libvlccore.lib - libvlccore.dylib - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + pkg_check_modules(libvlc REQUIRED IMPORTED_TARGET libvlc) + target_link_libraries( ll::libvlc INTERFACE PkgConfig::libvlc) + return() + endif() -target_link_libraries(ll::libvlc INTERFACE ${VLC_LIBRARY} ${VLCCORE_LIBRARY}) + use_prebuilt_binary(vlc-bin) + + find_library(VLC_LIBRARY + NAMES + libvlc.lib + libvlc.dylib + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(VLCCORE_LIBRARY + NAMES + libvlccore.lib + libvlccore.dylib + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + target_link_libraries(ll::libvlc INTERFACE ${VLC_LIBRARY} ${VLCCORE_LIBRARY}) +endif() diff --git a/indra/cmake/NDOF.cmake b/indra/cmake/NDOF.cmake index a8f63f945b1..60b29a57fe4 100644 --- a/indra/cmake/NDOF.cmake +++ b/indra/cmake/NDOF.cmake @@ -19,7 +19,12 @@ if (NDOF) ndofdev PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - target_link_libraries(ll::ndof INTERFACE ${NDOF_LIBRARY}) + if (LINUX) + include(SDL3) + target_link_libraries(ll::ndof INTERFACE ${NDOF_LIBRARY} ll::SDL3) + else() + target_link_libraries(ll::ndof INTERFACE ${NDOF_LIBRARY}) + endif() target_compile_definitions(ll::ndof INTERFACE LIB_NDOF=1) endif (NDOF) diff --git a/indra/cmake/OPENAL.cmake b/indra/cmake/OPENAL.cmake index ab1604aa22a..523a2d16f66 100644 --- a/indra/cmake/OPENAL.cmake +++ b/indra/cmake/OPENAL.cmake @@ -26,6 +26,7 @@ if (USE_OPENAL) NAMES OpenAL32 openal + OpenAL32.lib libopenal.dylib libopenal.so PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) @@ -33,6 +34,7 @@ if (USE_OPENAL) find_library(ALUT_LIBRARY NAMES alut + alut.lib libalut.dylib libalut.so PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) diff --git a/indra/cmake/PNG.cmake b/indra/cmake/PNG.cmake index 0c01e5ee78f..6a66f40385e 100644 --- a/indra/cmake/PNG.cmake +++ b/indra/cmake/PNG.cmake @@ -1,5 +1,7 @@ # -*- cmake -*- include(Prebuilt) +include(Linking) +include(ZLIBNG) include_guard() add_library( ll::libpng INTERFACE IMPORTED ) @@ -13,5 +15,5 @@ find_library(LIBPNG_LIBRARY libpng16.a PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) -target_link_libraries(ll::libpng INTERFACE ${LIBPNG_LIBRARY}) +target_link_libraries(ll::libpng INTERFACE ${LIBPNG_LIBRARY} ll::zlib-ng) target_include_directories(ll::libpng SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/libpng16) diff --git a/indra/cmake/Prebuilt.cmake b/indra/cmake/Prebuilt.cmake index 634cc15c21c..d0ab341d949 100644 --- a/indra/cmake/Prebuilt.cmake +++ b/indra/cmake/Prebuilt.cmake @@ -2,9 +2,6 @@ include_guard() include(FindAutobuild) -if(INSTALL_PROPRIETARY) - include(FindSCP) -endif(INSTALL_PROPRIETARY) set(PREBUILD_TRACKING_DIR ${AUTOBUILD_INSTALL_DIR}/cmake_tracking) # For the library installation process; @@ -40,8 +37,10 @@ macro (use_prebuilt_binary _binary) --install-dir=${AUTOBUILD_INSTALL_DIR} ${_binary} ") endif(DEBUG_PREBUILT) + message(STATUS "Installing ${_binary}...") execute_process(COMMAND "${AUTOBUILD_EXECUTABLE}" install + --skip-source-environment --install-dir=${AUTOBUILD_INSTALL_DIR} ${_binary} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake index 7cce190f6a5..39fd21c33f8 100644 --- a/indra/cmake/Python.cmake +++ b/indra/cmake/Python.cmake @@ -13,7 +13,7 @@ elseif (WINDOWS) foreach(hive HKEY_CURRENT_USER HKEY_LOCAL_MACHINE) # prefer more recent Python versions to older ones, if multiple versions # are installed - foreach(pyver 3.13 3.12 3.11 3.10 3.9 3.8 3.7) + foreach(pyver 3.14 3.13 3.12 3.11 3.10 3.9 3.8 3.7) list(APPEND regpaths "[${hive}\\SOFTWARE\\Python\\PythonCore\\${pyver}\\InstallPath]") endforeach() endforeach() diff --git a/indra/cmake/SDL3.cmake b/indra/cmake/SDL3.cmake new file mode 100644 index 00000000000..b37e1c64c27 --- /dev/null +++ b/indra/cmake/SDL3.cmake @@ -0,0 +1,19 @@ +# -*- cmake -*- +cmake_minimum_required( VERSION 3.13 FATAL_ERROR ) + +include(Linking) +include( Prebuilt ) +include_guard() + +add_library( ll::SDL3 INTERFACE IMPORTED ) + +use_system_binary( SDL3 ) +use_prebuilt_binary( SDL3 ) + +find_library( SDL3_LIBRARY + NAMES SDL3 SDL3.lib libSDL3.so libSDL3.dylib + PATHS "${LIBS_PREBUILT_DIR}/lib/release" REQUIRED) + +target_link_libraries( ll::SDL3 INTERFACE ${SDL3_LIBRARY}) +target_include_directories( ll::SDL3 SYSTEM INTERFACE "${LIBS_PREBUILT_DIR}/include/" ) + diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake index 8f135676d6a..afa1350ef04 100644 --- a/indra/cmake/UI.cmake +++ b/indra/cmake/UI.cmake @@ -1,35 +1,33 @@ # -*- cmake -*- include(Prebuilt) include(FreeType) +include(GLIB) +include_guard() add_library( ll::uilibraries INTERFACE IMPORTED ) if (LINUX) - target_compile_definitions(ll::uilibraries INTERFACE LL_GTK=1 LL_X11=1 ) - if( USE_CONAN ) - target_link_libraries( ll::uilibraries INTERFACE CONAN_PKG::gtk ) return() endif() - use_prebuilt_binary(gtk-atk-pango-glib) + + find_package(PkgConfig REQUIRED) + pkg_check_modules(WAYLAND_CLIENT wayland-client) + + if( WAYLAND_CLIENT_FOUND ) + target_compile_definitions( ll::uilibraries INTERFACE LL_WAYLAND=1) + else() + message("pkgconfig could not find wayland client, compiling without full wayland support") + endif() target_link_libraries( ll::uilibraries INTERFACE - atk-1.0 - gdk-x11-2.0 - gdk_pixbuf-2.0 - Xinerama - glib-2.0 - gmodule-2.0 - gobject-2.0 - gthread-2.0 - gtk-x11-2.0 - pango-1.0 - pangoft2-1.0 - pangox-1.0 - pangoxft-1.0 - Xinerama + ll::fontconfig ll::freetype - ) + ll::SDL3 + ll::glib + ll::gio + ) + endif (LINUX) if( WINDOWS ) target_link_libraries( ll::uilibraries INTERFACE diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 22c2156bb88..26437225505 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -9,21 +9,51 @@ # LINUX - Linux # WINDOWS - Windows +include_guard() + # Switches set here and in 00-Common.cmake must agree with # https://bitbucket.org/lindenlab/viewer-build-variables/src/tip/variables # Reading $LL_BUILD is an attempt to directly use those switches. -if ("$ENV{LL_BUILD}" STREQUAL "" AND "${LL_BUILD_ENV}" STREQUAL "" ) - message(FATAL_ERROR "Environment variable LL_BUILD must be set") -elseif("$ENV{LL_BUILD}" STREQUAL "") - set( ENV{LL_BUILD} "${LL_BUILD_ENV}" ) - message( "Setting ENV{LL_BUILD} to cached variable ${LL_BUILD_ENV}" ) +if ("$ENV{AUTOBUILD_ADDRSIZE}" STREQUAL "" AND "${AUTOBUILD_ADDRSIZE_ENV}" STREQUAL "" ) + message(FATAL_ERROR "Environment variable AUTOBUILD_ADDRSIZE must be set") +elseif("$ENV{AUTOBUILD_ADDRSIZE}" STREQUAL "") + set( ENV{AUTOBUILD_ADDRSIZE} "${AUTOBUILD_ADDRSIZE_ENV}" ) + message( "Setting ENV{AUTOBUILD_ADDRSIZE} to cached variable ${AUTOBUILD_ADDRSIZE_ENV}" ) else() - set( LL_BUILD_ENV "$ENV{LL_BUILD}" CACHE STRING "Save environment" FORCE ) + set( AUTOBUILD_ADDRSIZE_ENV "$ENV{AUTOBUILD_ADDRSIZE}" CACHE STRING "Save environment AUTOBUILD_ADDRSIZE" FORCE ) endif () -include_guard() -# Relative and absolute paths to subtrees. +if ("$ENV{AUTOBUILD_PLATFORM}" STREQUAL "" AND "${AUTOBUILD_PLATFORM_ENV}" STREQUAL "" ) + message(FATAL_ERROR "Environment variable AUTOBUILD_PLATFORM must be set") +elseif("$ENV{AUTOBUILD_PLATFORM}" STREQUAL "") + set( ENV{AUTOBUILD_PLATFORM} "${AUTOBUILD_PLATFORM_ENV}" ) + message( "Setting ENV{AUTOBUILD_PLATFORM} to cached variable ${AUTOBUILD_PLATFORM_ENV}" ) +else() + set( AUTOBUILD_PLATFORM_ENV "$ENV{AUTOBUILD_PLATFORM}" CACHE STRING "Save environment AUTOBUILD_PLATFORM" FORCE ) +endif () +# Switches set here and in 00-Common.cmake must agree with +# https://bitbucket.org/lindenlab/viewer-build-variables/src/tip/variables +# Reading $LL_BUILD is an attempt to directly use those switches. +if ("$ENV{LL_BUILD_RELEASE}" STREQUAL "" AND "${LL_BUILD_RELEASE_ENV}" STREQUAL "" ) + message(FATAL_ERROR "Environment variable LL_BUILD_RELEASE must be set") +elseif("$ENV{LL_BUILD_RELEASE}" STREQUAL "") + set( ENV{LL_BUILD_RELEASE} "${LL_BUILD_RELEASE_ENV}" ) + message( "Setting ENV{LL_BUILD_RELEASE} to cached variable ${LL_BUILD_RELEASE_ENV}" ) +else() + set( LL_BUILD_RELEASE_ENV "$ENV{LL_BUILD_RELEASE}" CACHE STRING "Save environment RELEASE" FORCE ) +endif () + +if ("$ENV{LL_BUILD_RELWITHDEBINFO}" STREQUAL "" AND "${LL_BUILD_RELWITHDEBINFO_ENV}" STREQUAL "" ) + message(FATAL_ERROR "Environment variable LL_BUILD_RELWITHDEBINFO must be set") +elseif("$ENV{LL_BUILD_RELWITHDEBINFO}" STREQUAL "") + set( ENV{LL_BUILD_RELWITHDEBINFO} "${LL_BUILD_RELWITHDEBINFO_ENV}" ) + message( "Setting ENV{LL_BUILD_RELWITHDEBINFO} to cached variable ${LL_BUILD_RELWITHDEBINFO_ENV}" ) +else() + set( LL_BUILD_RELWITHDEBINFO_ENV "$ENV{LL_BUILD_RELWITHDEBINFO}" CACHE STRING "Save environment RELWITHDEBINFO" FORCE ) +endif () + +# Relative and absolute paths to subtrees. if(NOT DEFINED COMMON_CMAKE_DIR) set(COMMON_CMAKE_DIR "${CMAKE_SOURCE_DIR}/cmake") endif(NOT DEFINED COMMON_CMAKE_DIR) @@ -67,7 +97,7 @@ set(TEMPLATE_VERIFIER_MASTER_URL "https://github.com/secondlife/master-message-t if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING - "Build type. One of: Debug Release RelWithDebInfo" FORCE) + "Build type. One of: Release RelWithDebInfo" FORCE) endif (NOT CMAKE_BUILD_TYPE) # If someone has specified an address size, use that to determine the @@ -127,16 +157,12 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(CMAKE_SYSTEM_LIBRARY_PATH /usr/lib/${DPKG_ARCH} /usr/local/lib/${DPKG_ARCH} ${CMAKE_SYSTEM_LIBRARY_PATH}) endif (DPKG_RESULT EQUAL 0) - include(ConfigurePkgConfig) - - if (INSTALL_PROPRIETARY) - # Only turn on headless if we can find osmesa libraries. - include(FindPkgConfig) - #pkg_check_modules(OSMESA osmesa) - #if (OSMESA_FOUND) - # set(BUILD_HEADLESS ON CACHE BOOL "Build headless libraries.") - #endif (OSMESA_FOUND) - endif (INSTALL_PROPRIETARY) + # Only turn on headless if we can find osmesa libraries. + find_package(PkgConfig) + pkg_check_modules(OSMESA osmesa IMPORTED_TARGET GLOBAL) + if (OSMESA_FOUND) + set(BUILD_HEADLESS ON CACHE BOOL "Build headless libraries.") + endif (OSMESA_FOUND) endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake index cae68fbc119..23fd477ba89 100644 --- a/indra/cmake/ViewerMiscLibs.cmake +++ b/indra/cmake/ViewerMiscLibs.cmake @@ -5,11 +5,8 @@ if (LINUX) #use_prebuilt_binary(libuuid) add_library( ll::fontconfig INTERFACE IMPORTED ) - if( NOT USE_CONAN ) - use_prebuilt_binary(fontconfig) - else() - target_link_libraries( ll::fontconfig INTERFACE CONAN_PKG::fontconfig ) - endif() + find_package(Fontconfig REQUIRED) + target_link_libraries( ll::fontconfig INTERFACE Fontconfig::Fontconfig ) endif (LINUX) if( NOT USE_CONAN ) diff --git a/indra/cmake/ZLIBNG.cmake b/indra/cmake/ZLIBNG.cmake index a6d67489e71..9f8f12d973a 100644 --- a/indra/cmake/ZLIBNG.cmake +++ b/indra/cmake/ZLIBNG.cmake @@ -1,6 +1,7 @@ # -*- cmake -*- include(Prebuilt) +include(Linking) include_guard() add_library( ll::zlib-ng INTERFACE IMPORTED ) diff --git a/indra/cmake/bugsplat.cmake b/indra/cmake/bugsplat.cmake index 509981d72cd..8916cb282c1 100644 --- a/indra/cmake/bugsplat.cmake +++ b/indra/cmake/bugsplat.cmake @@ -1,18 +1,19 @@ -if (INSTALL_PROPRIETARY) +if (INSTALL_PROPRIETARY AND NOT LINUX) # Note that viewer_manifest.py makes decision based on BUGSPLAT_DB and not USE_BUGSPLAT if (BUGSPLAT_DB) set(USE_BUGSPLAT ON CACHE BOOL "Use the BugSplat crash reporting system") else (BUGSPLAT_DB) set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system") endif (BUGSPLAT_DB) -else (INSTALL_PROPRIETARY) +else () set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system") -endif (INSTALL_PROPRIETARY) + set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name") +endif () include_guard() add_library( ll::bugsplat INTERFACE IMPORTED ) -if (USE_BUGSPLAT) +if (USE_BUGSPLAT AND NOT LINUX) include(Prebuilt) use_prebuilt_binary(bugsplat) if (WINDOWS) @@ -36,6 +37,7 @@ if (USE_BUGSPLAT) set_property( TARGET ll::bugsplat APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS LL_BUGSPLAT) else() - set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name") -endif (USE_BUGSPLAT) + set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system" FORCE) + set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name" FORCE) +endif () diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index 6744c8d8a44..40a1036597b 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -28,7 +28,7 @@ set(llappearance_SOURCE_FILES llviewervisualparam.cpp llavatarappearancedefines.cpp ) - + set(llappearance_HEADER_FILES CMakeLists.txt @@ -77,6 +77,7 @@ if (BUILD_HEADLESS) llcharacter llinventory llimage + llrenderheadless llfilesystem llmath llxml diff --git a/indra/llappearance/llavatarappearancedefines.cpp b/indra/llappearance/llavatarappearancedefines.cpp index 47798844bce..f26795123f3 100644 --- a/indra/llappearance/llavatarappearancedefines.cpp +++ b/indra/llappearance/llavatarappearancedefines.cpp @@ -260,7 +260,7 @@ ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextu return getBakedTexture(index)->mTextureIndex; } -EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::string name) +EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(const std::string& name) const { U8 index = 0; while (index < BAKED_NUM_INDICES) @@ -277,7 +277,7 @@ EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::stri return BAKED_NUM_INDICES; } -EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(std::string name) +EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(const std::string& name) const { U8 index = 0; while (index < BAKED_NUM_INDICES) diff --git a/indra/llappearance/llavatarappearancedefines.h b/indra/llappearance/llavatarappearancedefines.h index 50a72a45a5a..0f9edc1ca0d 100644 --- a/indra/llappearance/llavatarappearancedefines.h +++ b/indra/llappearance/llavatarappearancedefines.h @@ -238,8 +238,8 @@ class LLAvatarAppearanceDictionary ETextureIndex bakedToLocalTextureIndex(EBakedTextureIndex t) const; // find a baked texture index based on its name - EBakedTextureIndex findBakedByRegionName(std::string name); - EBakedTextureIndex findBakedByImageName(std::string name); + EBakedTextureIndex findBakedByRegionName(const std::string& name) const; + EBakedTextureIndex findBakedByImageName(const std::string& name) const; // Given a texture entry, determine which wearable type owns it. LLWearableType::EType getTEWearableType(ETextureIndex index) const; diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index b3800e69811..389efe47a9a 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -435,6 +435,31 @@ const std::string LLTexLayerSet::getBodyRegionName() const return mInfo->mBodyRegion; } +// virtual +void LLTexLayerSet::asLLSD(LLSD& sd) const +{ + sd["visible"] = LLSD::Boolean(isVisible()); + LLSD layer_list_sd; + layer_list_t::const_iterator layer_iter = mLayerList.begin(); + layer_list_t::const_iterator layer_end = mLayerList.end(); + for(; layer_iter != layer_end; ++layer_iter) + { + LLSD layer_sd; + LLTexLayerInterface* layer = (*layer_iter); + if (layer) + { + layer->asLLSD(layer_sd); + } + layer_list_sd.append(layer_sd); + } + LLSD mask_list_sd; + LLSD info_sd; + sd["layers"] = layer_list_sd; + sd["masks"] = mask_list_sd; + sd["info"] = info_sd; +} + + void LLTexLayerSet::destroyComposite() { if( mComposite ) diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index 876ea6f6007..6b501474d68 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -220,6 +220,8 @@ class LLTexLayerSet static bool sHasCaches; + virtual void asLLSD(LLSD& sd) const; + protected: typedef std::vector layer_list_t; layer_list_t mLayerList; diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h index 5e785e4f3ed..116eb3bee02 100644 --- a/indra/llappearance/lltexlayerparams.h +++ b/indra/llappearance/lltexlayerparams.h @@ -30,6 +30,7 @@ #include "llpointer.h" #include "v4color.h" #include "llviewervisualparam.h" +#include class LLAvatarAppearance; class LLImageRaw; diff --git a/indra/llappearanceutility/CMakeLists.txt b/indra/llappearanceutility/CMakeLists.txt new file mode 100644 index 00000000000..1d4e5309ba6 --- /dev/null +++ b/indra/llappearanceutility/CMakeLists.txt @@ -0,0 +1,78 @@ +# -*- cmake -*- + +project(appearance_utility) + +include(00-Common) +include(Boost) +include(LLAppearance) +include(LLCommon) +include(LLImage) +include(LLMath) +include(LLWindow) +include(Linking) + +set(appearance_utility_SOURCE_FILES + appearance_utility.cpp + llappappearanceutility.cpp + llbakingavatar.cpp + llbakingjoint.cpp + llbakingjointmesh.cpp + llbakingprocess.cpp + llbakingshadermgr.cpp + llbakingtexlayer.cpp + llbakingtexture.cpp + llbakingwearable.cpp + llbakingwearablesdata.cpp + llbakingwindow.cpp + llprocessparams.cpp + llprocessskin.cpp + llprocesstexture.cpp + ) + +set(appearance_utility_HEADER_FILES + CMakeLists.txt + llappappearanceutility.h + llbakingavatar.h + llbakingjoint.h + llbakingjointmesh.h + llbakingprocess.h + llbakingshadermgr.h + llbakingtexlayer.h + llbakingtexture.h + llbakingwearable.h + llbakingwearablesdata.h + llbakingwindow.h + llprocessparams.h + llprocessskin.h + llprocesstexture.h + ) + +set_source_files_properties(${appearance_utility_HEADER_FILES} + PROPERTIES HEADER_FILES_ONLY TRUE) + +list(APPEND appearance_utility_SOURCE_FILES ${appearance_utility_HEADER_FILES}) + +add_executable(appearance-utility-bin ${appearance_utility_SOURCE_FILES}) + +target_link_libraries(appearance-utility-bin + llcharacter + llinventory + llappearance + llwindow + llrender + llxml + ) + +if (BUILD_HEADLESS) + add_executable(appearance-utility-headless-bin ${appearance_utility_SOURCE_FILES}) + + target_link_libraries(appearance-utility-headless-bin + llcharacter + llinventory + llappearanceheadless + llwindowheadless + llrenderheadless + llxml + ) +endif (BUILD_HEADLESS) + diff --git a/indra/llappearanceutility/README.md b/indra/llappearanceutility/README.md new file mode 100644 index 00000000000..21019ffd27b --- /dev/null +++ b/indra/llappearanceutility/README.md @@ -0,0 +1,33 @@ +# llappearanceutility + +This directory contains the appearance utility employed by the bake service to process avatar textures and handle various other appearance-related functions. Please note that this utility is currently configured to build only on Linux systems. + +## Prerequisites + +Ensure the following prerequisites are met before building and testing the utility: + +- **X11 Display**: Ensure an X11 display is available, either virtual or physical, with the `DISPLAY` environment variable set appropriately (e.g., `DISPLAY=:1`). +- **Linux Build Environment**: Confirm that the Second Life Viewer can be built on your Linux system. + +## Testing + +Given the constraints with GitHub runners, we instead utilize Behavior-Driven Development (BDD) tests to evaluate the `llappearanceutility` through the bake service. For local development, test inputs and their expected outputs are provided below. + +### Test Commands + +1. **Baking Textures**: + ```sh + appearance-utility-bin --agent-id de494a4f-f01a-47a4-98cf-c94ef9ecca38 --texture /viewer/indra/llappearanceutility/tests/texture.llsd.binary > /viewer/indra/llappearanceutility/tests/texture.llsd.output + ``` + +2. **Generating Bake Parameters**: + ```sh + appearance-utility-bin --agent-id de494a4f-f01a-47a4-98cf-c94ef9ecca38 --params /viewer/indra/llappearanceutility/tests/params.xml > /viewer/indra/llappearanceutility/tests/params.xml.output + ``` + +3. **Calculating Joint Offsets**: + ```sh + appearance-utility-bin --agent-id de494a4f-f01a-47a4-98cf-c94ef9ecca38 --joint-offsets /viewer/indra/llappearanceutility/tests/joint-offsets.xml > /viewer/indra/llappearanceutility/tests/joint-offsets.xml.output + ``` + +These commands will execute the utility with specific test inputs and direct the output to corresponding files for validation. \ No newline at end of file diff --git a/indra/llappearanceutility/appearance_utility.cpp b/indra/llappearanceutility/appearance_utility.cpp new file mode 100644 index 00000000000..88034cd1712 --- /dev/null +++ b/indra/llappearanceutility/appearance_utility.cpp @@ -0,0 +1,66 @@ +/** + * @file appearance_utility.cpp + * @author Don Kjer , Nyx Linden + * @brief Utility for processing avatar appearance without a full viewer implementation. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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$ + */ + +// linden includes +#include "linden_common.h" +#include "llapr.h" + +// project includes +#include "llappappearanceutility.h" + +int main(int argc, char** argv) +{ + // Create an application instance. + ll_init_apr(); + LLAppAppearanceUtility* app = new LLAppAppearanceUtility(argc, argv); + + // Assume success, unless exception is thrown. + EResult rv = RV_SUCCESS; + try + { + // Process command line and initialize system. + if (app->init()) + { + // Run process. + app->frame(); + } + } + catch (LLAppException& e) + { + // Deal with errors. + rv = e.getStatusCode(); + } + + // Clean up application instance. + app->cleanup(); + delete app; + ll_cleanup_apr(); + + return (int) rv; +} + + diff --git a/indra/llappearanceutility/llappappearanceutility.cpp b/indra/llappearanceutility/llappappearanceutility.cpp new file mode 100644 index 00000000000..d223c859abc --- /dev/null +++ b/indra/llappearanceutility/llappappearanceutility.cpp @@ -0,0 +1,681 @@ +/** + * @file llappappearanceutility.cpp + * @brief Implementation of LLAppAppearanceUtility class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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 +#include +#include +#include "boost/bind.hpp" + +// linden includes +#include "linden_common.h" + +#include "llapr.h" +#include "llerrorcontrol.h" +#include "llfasttimer.h" +#include "llgl.h" +#include "llmd5.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "llsdutil.h" +#include "llquantize.h" +#include "lltreeiterators.h" +#include "v3color.h" +#include "llwindow.h" +#include "lltrace.h" + +// appearance includes +#include "llavatarappearance.h" +#include "llwearabletype.h" + +// project includes +#include "llappappearanceutility.h" +#include "llbakingprocess.h" +#include "llprocessparams.h" +#include "llprocesstexture.h" +#include "llprocessskin.h" + +const std::string NOTHING_EXTRA(""); + +//////////////////////////////////////////// +// LLAppException +//////////////////////////////////////////// + +static const std::string MESSAGE_RV_UNKNOWN("Unknown error."); +static const std::string MESSAGE_RV_ARGUMENTS +("Invalid arguments: "); +static const std::string MESSAGE_RV_UNABLE_OPEN("Unable to open file: "); +static const std::string MESSAGE_RV_UNABLE_TO_PARSE("Unable to parse input LLSD."); +static const std::string MESSAGE_RV_UNABLE_TO_DECODE("Unable to decode input J2C."); +static const std::string MESSAGE_RV_UNABLE_TO_ENCODE("Unable to encode output J2C."); +static const std::string MESSAGE_RV_UNABLE_TO_INIT_GL("Unable to initialize GL."); +static const std::string MESSAGE_RV_UNABLE_TO_BAKE("Unable to bake texture."); +static const std::string MESSAGE_RV_INVALID_SKIN_BLOCK("Invalid skin block."); +static const std::string MESSAGE_DUPLICATE_MODES = "Cannot specify more than one process mode."; + + +LLAppException::LLAppException(EResult status_code, const std::string& extra) : + mStatusCode(status_code) +{ + switch(status_code) + { + case RV_UNKNOWN_ERROR: + printErrorLLSD("unknown", MESSAGE_RV_UNKNOWN); + case RV_BAD_ARGUMENTS: + printErrorLLSD("arguments", MESSAGE_RV_ARGUMENTS + extra); + break; + case RV_UNABLE_OPEN: + printErrorLLSD("file", MESSAGE_RV_UNABLE_OPEN + extra); + break; + case RV_UNABLE_TO_PARSE: + printErrorLLSD("input", MESSAGE_RV_UNABLE_TO_PARSE + extra); + break; + case RV_UNABLE_TO_DECODE: + printErrorLLSD("input", MESSAGE_RV_UNABLE_TO_DECODE + extra); + break; + case RV_UNABLE_TO_ENCODE: + printErrorLLSD("input", MESSAGE_RV_UNABLE_TO_ENCODE + extra); + break; + case RV_UNABLE_TO_INIT_GL: + printErrorLLSD("input", MESSAGE_RV_UNABLE_TO_INIT_GL + extra); + break; + case RV_UNABLE_TO_BAKE: + printErrorLLSD("input", MESSAGE_RV_UNABLE_TO_BAKE + extra); + break; + case RV_INVALID_SKIN_BLOCK: + printErrorLLSD("input", MESSAGE_RV_INVALID_SKIN_BLOCK + extra); + break; + default: + printErrorLLSD("arguments", "Unknown exception."); + break; + } +} + +void LLAppException::printErrorLLSD(const std::string& key, const std::string& message) +{ + LLSD error_llsd; + error_llsd["success"] = false; + error_llsd["error"]["key"] = key; + error_llsd["error"]["message"] = message; + + std::cerr << LLSDOStreamer(error_llsd); +} + + + +//////////////////////////////////////////// +// LLAppAppearanceUtility +//////////////////////////////////////////// + +///////// Option Parsing ///////// + +// Simple usage command. +class LLProcessUsage : public LLBakingProcess +{ +public: + LLProcessUsage(LLAppAppearanceUtility* app) : + LLBakingProcess(app) {} + void process(std::ostream& output) override + { + mApp->usage(output); + } +}; + + +static const apr_getopt_option_t APPEARANCE_UTILITY_OPTIONS[] = +{ + {"params", 'p', 0, "Generate appearance parameters for an agent."}, + {"texture", 't', 0, "Generate baked texture for a slot."}, + {"output", 'o', 1, "The output file to write to. Default is stdout"}, + {"agent-id", 'a', 1, "The agent-id of the user."}, + {"bake-size", 'b', 1, "The bake texture size. eg use 512 for 512*512 textures, 1024 for 1024*1024 textures" }, + //{"grid", 'g', 1, "The grid."}, + {"debug", 'd', 0, "Enable debug spam. Default is warn/info spam only."}, + {"treemap", 'm', 1, "Output LLFrameTimer to specified file in graphviz treemap/pachwork format."}, + {"threshold", 's', 1, "Percent threshold of max LLFrameTimer time in order to appear on treemap. Default is 1%."}, + {"joint-offsets",'j',0,"Extract joint positions from skin."}, + {"help", 'h', 0, "Print the help message."}, + {0, 0, 0, 0} +}; + +void LLAppAppearanceUtility::usage(std::ostream& ostr) +{ + ostr << "Utilities for processing agent appearance data." + << std::endl << std::endl + << "Usage:" << std::endl + << "\t" << mAppName << " [options] filename" << std::endl << std::endl + << "Will read from stdin if filename is set to '-'." << std::endl << std::endl + << "Options:" << std::endl; + const apr_getopt_option_t* option = &APPEARANCE_UTILITY_OPTIONS[0]; + while(option->name) + { + ostr << "\t--" << option->name << "\t\t" + << option->description << std::endl; + ++option; + } + ostr << std::endl << "Return Values:" << std::endl + << "\t0\t\tSuccess." << std::endl + << "\t1\t\tUnknown error." << std::endl + << "\t2\t\tBad arguments." << std::endl + << "\t3\t\tUnable to open file. Possibly wrong filename" + << " or bad permissions." << std::endl + << "\t4\t\tUnable to parse input LLSD." << std::endl + << std::endl + << "Output:" << std::endl + << "If a non-zero status code is returned, additional error information" + << " will be returned on stderr." << std::endl + << "* This will be in the form of an LLSD document." << std::endl + << "* Check ['error']['message'] to get a human readable message." << std::endl + << "If a zero status code is returned, processed output will be written" + << " to the file specified by --out (or stdout, if not specified)." << std::endl + << std::endl + << std::endl; +} + + +/////// LLApp Interface //////// + +LLAppAppearanceUtility::LLAppAppearanceUtility(int argc, char** argv) : + LLApp(), + mArgc(argc), + mArgv(argv), + mProcess(nullptr), + mInput(nullptr), + mOutput(nullptr), + mAppName(argv[0]), + mDebugMode(false), + mTreeMapThreshold(1), + mBakeTextureSize(512) +{ +} + +// virtual +LLAppAppearanceUtility::~LLAppAppearanceUtility() +{ +} + +void LLAppAppearanceUtility::verifyNoProcess() +{ + if (mProcess) + { + std::cerr << "Invalid arguments. " << MESSAGE_DUPLICATE_MODES << std::endl; + usage(std::cerr); + throw LLAppException(RV_BAD_ARGUMENTS, MESSAGE_DUPLICATE_MODES); + } +} + +void LLAppAppearanceUtility::parseArguments() +{ + ////// BEGIN OPTION PARSING ////// + // Check for '-' as last option, since apr doesn't seem to like that. + if (std::string(mArgv[mArgc-1]) == "-") + { + mInputFilename.assign("-"); + mArgc--; + } + + apr_status_t apr_err; + const char* opt_arg = nullptr; + int opt_id = 0; + apr_getopt_t* os = nullptr; + if(APR_SUCCESS != apr_getopt_init(&os, gAPRPoolp, mArgc, mArgv)) + { + std::cerr << "Unable to initialize apr" << std::endl; + throw LLAppException(RV_UNKNOWN_ERROR); + } + + //std::string grid; + while(true) + { + apr_err = apr_getopt_long(os, APPEARANCE_UTILITY_OPTIONS, &opt_id, &opt_arg); + if(APR_STATUS_IS_EOF(apr_err)) break; + if(apr_err) + { + char buf[MAX_STRING]; /* Flawfinder: ignore */ + std::cerr << "Error parsing options: " + << apr_strerror(apr_err, buf, MAX_STRING) << std::endl; + usage(std::cerr); + throw LLAppException(RV_BAD_ARGUMENTS, buf); + } + switch (opt_id) + { + case 'h': + verifyNoProcess(); + mProcess = new LLProcessUsage(this); + break; + case 'p': + verifyNoProcess(); + mProcess = new LLProcessParams(this); + break; + case 't': + verifyNoProcess(); + mProcess = new LLProcessTexture(this); + break; + case 'j': + verifyNoProcess(); + mProcess = new LLProcessSkin( this ); + break; + case 'o': + mOutputFilename.assign(opt_arg); + break; + case 'a': + mAgentID.set(opt_arg); + if (mAgentID.isNull()) + { + const char* INVALID_AGENT_ID="agent-id must be a valid uuid."; + std::cerr << "Invalid arguments. " << INVALID_AGENT_ID << std::endl; + usage(std::cerr); + throw LLAppException(RV_BAD_ARGUMENTS, INVALID_AGENT_ID); + } + break; + case 'b': + mBakeTextureSize = atoi(opt_arg); + break; + //case 'g': + // grid = opt_arg; + // break; + case 'd': + mDebugMode = true; + break; + case 'm': + mTreeMapFilename.assign(opt_arg); + break; + case 's': + mTreeMapThreshold = atoi(opt_arg); + break; + default: + usage(std::cerr); + throw LLAppException(RV_BAD_ARGUMENTS, "Unknown option."); + } + } + + if ("-" != mInputFilename) + { + bool valid_input_filename = false; + // Try to grab the input filename. + if (os->argv && os->argv[os->ind]) + { + mInputFilename.assign(os->argv[os->ind]); + if (! mInputFilename.empty() ) + { + valid_input_filename = true; + } + } + if (!valid_input_filename) + { + const char* INVALID_FILENAME="Must specify input file."; + std::cerr << "Invalid arguments. " << INVALID_FILENAME << std::endl; + usage(std::cerr); + throw LLAppException(RV_BAD_ARGUMENTS, INVALID_FILENAME); + } + } + + ////// END OPTION PARSING ////// +} + +void LLAppAppearanceUtility::validateArguments() +{ + ///// BEGIN ARGUMENT VALIDATION ///// + + // Make sure we have a command specified. + if (!mProcess) + { + const char* INVALID_MODE="No process mode specified."; + std::cerr << "Invalid arguments. " << INVALID_MODE + << std::endl; + usage(std::cerr); + throw LLAppException(RV_BAD_ARGUMENTS, INVALID_MODE); + } + + ///// END ARGUMENT VALIDATION ///// +} + +void LLAppAppearanceUtility::initializeIO() +{ + ///// BEGIN OPEN INPUT FILE //// + + if ( "-" == mInputFilename ) + { + // Read unformated data from stdin in to memory. + std::stringstream* data = new std::stringstream(); + const S32 BUFFER_SIZE = BUFSIZ; + char buffer[BUFFER_SIZE]; + while (true) + { + std::cin.read(buffer, BUFFER_SIZE); + // Check if anything out of the ordinary happened. + if (!std::cin) + { + // See if something 'really bad' happened, or if we just + // used up all of our buffer. + if (std::cin.bad()) + { + std::cerr << "Problem reading standard input." << std::endl; + delete data; + throw (RV_UNKNOWN_ERROR); + } + else + { + // Output normally. + data->write(buffer, std::cin.gcount()); + if (std::cin.eof()) break; + + // Clear this problem. We have handled it. + std::cin.clear(); + } + } + else + { + data->write(buffer, std::cin.gcount()); + if (std::cin.eof()) break; + } + } + mInput = data; + } + else + { + // Make sure we can open the input file. + std::ifstream* input_file = new std::ifstream(); + input_file->open( mInputFilename.c_str(), std::fstream::in | std::fstream::binary ); + if ( input_file->fail()) + { + std::cerr << "Couldn't open input file '" << mInputFilename << "'." << std::endl; + delete input_file; + throw LLAppException(RV_UNABLE_OPEN, mInputFilename); + } + mInput = input_file; + } + ///// END OPEN INPUT FILE //// + + ///// BEGIN OPEN OUTPUT FILE //// + + if ("" == mOutputFilename) + { + mOutput = &std::cout; + } + else + { + // Make sure we can open the output file. + std::fstream* output_file = new std::fstream(); + output_file->open( mOutputFilename.c_str(), std::fstream::out ); + if ( output_file->fail() ) + { + std::cerr << "Couldn't open output file '" << mOutputFilename << "'." << std::endl; + delete output_file; + throw LLAppException(RV_UNABLE_OPEN, mOutputFilename); + } + mOutput = output_file; + } + ///// END OPEN OUTPUT FILE //// + + ///// BEGIN INPUT PARSING //// + if (mProcess) + { + mProcess->parseInput( *mInput ); + } + ///// END INPUT PARSING //// +} + +class LLPassthroughTranslationBridge : public LLTranslationBridge +{ +public: + virtual std::string getString(const std::string &xml_desc) + { + // Just pass back the input string. + return xml_desc; + } +}; + + +bool LLAppAppearanceUtility::init() +{ + parseArguments(); + + bool log_to_stderr = true; + LLError::initForApplication(".", ".", true); + if (mDebugMode) + { + mRecording.start(); + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + } + else + { + LLError::setDefaultLevel(LLError::LEVEL_WARN); + } + + validateArguments(); + + LL_DEBUGS() << "BakeSize: " << mBakeTextureSize << LL_ENDL; + + // Initialize classes. + // Values taken from settings.xml. + const bool USE_TEXTURE_NEW_BYTE_RANGE=true; + const S32 TEXTURE_REVERSE_BYTE_RANGE=50; + LLImage::initClass(USE_TEXTURE_NEW_BYTE_RANGE, TEXTURE_REVERSE_BYTE_RANGE); + const bool SKIP_ANALYZE_ALPHA=true; + + LLTranslationBridge::ptr_t trans = std::make_shared(); + LLWearableType::initParamSingleton(trans); + + // *TODO: Create a texture bridge? + LLAvatarAppearance::initClass(); + + initializeIO(); + if (mProcess) + { + mProcess->init(); + } + return true; +} + + +void add_cluster(LLTrace::Recording& recording, std::ostream& tree, LLTrace::BlockTimerStatHandle& node, std::vector < S32 > & clusters, F64Milliseconds threshold) +{ + LLMD5 hash; + hash.update((const unsigned char*)node.getName().c_str(), node.getName().size()); + hash.finalize(); + char buf[33]; + hash.hex_digest(buf); + buf[6] = 0; + LLColor3 color(buf); + if (color.brightness() < 0.25f) + { + color.normalize(); + } + std::ostringstream color_str; + color_str << "#" << std::hex << std::setfill('0') << std::setw(2) + << (S32) F32_to_U8(color.mV[0], 0.0f, 1.0f) + << (S32) F32_to_U8(color.mV[1], 0.0f, 1.0f) + << (S32) F32_to_U8(color.mV[2], 0.0f, 1.0f); + + std::vector::iterator iter = clusters.begin(); + std::vector::iterator end = clusters.end(); + std::ostringstream padding; + for(; iter != end; ++iter) + { + padding << " "; + } + + std::ostringstream node_id; + bool first = true; + iter = clusters.begin(); + for(; iter != end; ++iter) + { + if (!first) + { + node_id << "_"; + } + first = false; + node_id << (*iter); + } + + if (node.getChildren().size() == 0) + { + F64Milliseconds leaf_time_ms(recording.getSum(node)); + if (leaf_time_ms > threshold) + { + tree << padding.str() << "n" << node_id.str() << " [" + << "label=\"" << node.getName() << " (" << leaf_time_ms.value() << ")\" " + << "fillcolor=\"" << color_str.str() << "\" " + << "area=" << leaf_time_ms.value() / 10 << "]" << std::endl; + } + } + else + { + if (clusters.size()) + { + tree << padding.str() << "subgraph cluster" << node_id.str(); + tree << " {" << std::endl; + } + + S32Milliseconds node_area(recording.getSum(node)); + std::vector::iterator child_iter = node.getChildren().begin(); + for (S32 num=0; child_iter != node.getChildren().end(); ++child_iter, ++num) + { + clusters.push_back(num); + add_cluster(recording, tree, *(*child_iter), clusters, threshold); + clusters.pop_back(); + node_area -= recording.getSum(*(*child_iter)); + } + + S32Milliseconds node_time_ms(node_area); + if (node_time_ms > threshold) + { + tree << padding.str() << "n" << node_id.str() << " [" + << "label=\"" << node.getName() << " (" << node_time_ms.value() << ")\" " + << "fillcolor=\"" << color_str.str() << "\" " + << "area=" << node_time_ms.value() / 10 << "]" << std::endl; + } + if (clusters.size()) + { + tree << padding.str() << "}" << std::endl;; + } + } +} + +bool LLAppAppearanceUtility::cleanup() +{ + if (mProcess) + { + mProcess->cleanup(); + } + + // Spam fast timer information in debug mode. + if (mDebugMode) + { + mRecording.stop(); + LLTrace::BlockTimer::processTimes(); + + S32Milliseconds max_time_ms(0); + for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(LLTrace::BlockTimer::getRootTimeBlock()); + it != LLTrace::end_block_timer_tree_df(); + ++it) + { + LLTrace::BlockTimerStatHandle* idp = (*it); + // Skip near-zero time leafs. + S32Milliseconds leaf_time_ms(mRecording.getSum(*idp)); + if (leaf_time_ms > max_time_ms) max_time_ms = leaf_time_ms; + if ((S32Milliseconds)0 == leaf_time_ms) continue; + + std::vector< LLTrace::BlockTimerStatHandle* > parents; + LLTrace::BlockTimerStatHandle* parentp = idp->getParent(); + while (parentp) + { + parents.push_back(parentp); + if (parentp->getParent() == parentp) break; + parentp = parentp->getParent(); + } + + std::ostringstream fullname; + bool is_first = true; + for ( std::vector< LLTrace::BlockTimerStatHandle* >::reverse_iterator iter = parents.rbegin(); + iter != parents.rend(); ++iter) + { + // Skip root + if (is_first) + { + is_first = false; + continue; + } + LLTrace::BlockTimerStatHandle* parent_idp = (*iter); + U32Milliseconds time_ms(mRecording.getSum(parent_idp->selfTime())); + fullname << parent_idp->getName() << " "; + fullname << "("; + if (time_ms > (U32Milliseconds)0) + { + fullname << time_ms.value() << " ms, "; + } + fullname << mRecording.getSum(parent_idp->callCount()) << " call)-> "; + } + LL_DEBUGS() << fullname.str() << LL_ENDL; + } + if (!mTreeMapFilename.empty()) + { + std::ofstream tree(mTreeMapFilename.c_str()); + tree << "graph G {" << std::endl; + tree << " node[style=filled]" << std::endl; + + LLTrace::BlockTimerStatHandle& root = LLTrace::BlockTimer::getRootTimeBlock(); + std::vector clusters; + add_cluster(mRecording, tree, root, clusters, (((F32) mTreeMapThreshold / 100.f) * max_time_ms) ); + + tree << "}" << std::endl; + + LL_DEBUGS() << "To generate a treemap of LLFrameTimer results, run:" << LL_ENDL; + LL_DEBUGS() << "patchwork " << mTreeMapFilename << " -Tpng > rendered.png" << LL_ENDL; + } + } + + LLAvatarAppearance::cleanupClass(); + LLImageGL::cleanupClass(); + LLImage::cleanupClass(); + + if (mProcess) + { + delete mProcess; + mProcess = nullptr; + } + if ("-" != mInputFilename && mInput) + { + static_cast(mInput)->close(); + } + if ("" != mOutputFilename && mOutput) + { + static_cast(mOutput)->close(); + delete mOutput; + mOutput = nullptr; + } + delete mInput; + mInput = nullptr; + return true; +} + +bool LLAppAppearanceUtility::frame() +{ + // This isn't really a loop, for this application. We just execute the requested command. + mProcess->process(*mOutput); + return true; +} + diff --git a/indra/llappearanceutility/llappappearanceutility.h b/indra/llappearanceutility/llappappearanceutility.h new file mode 100644 index 00000000000..80d1e8b1bf6 --- /dev/null +++ b/indra/llappearanceutility/llappappearanceutility.h @@ -0,0 +1,108 @@ +/** + * @file llappappearanceutility.h + * @brief Declaration of LLAppAppearanceUtility class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLAPPAPPEARANCEUTILITY_H +#define LL_LLAPPAPPEARANCEUTILITY_H + +#include + +#include "llapp.h" +#include "lltracerecording.h" + +enum EResult +{ + RV_SUCCESS = 0, + RV_UNKNOWN_ERROR, + RV_BAD_ARGUMENTS, + RV_UNABLE_OPEN, + RV_UNABLE_TO_PARSE, + RV_UNABLE_TO_DECODE, + RV_UNABLE_TO_ENCODE, + RV_UNABLE_TO_INIT_GL, + RV_UNABLE_TO_BAKE, + RV_INVALID_SKIN_BLOCK, +}; + +extern const std::string NOTHING_EXTRA; + +class LLAppAppearanceUtility; +class LLBakingProcess; + +// Translate error status into error messages. +class LLAppException : public std::exception +{ +public: + LLAppException(EResult status_code, const std::string& extra = NOTHING_EXTRA); + EResult getStatusCode() { return mStatusCode; } + +private: + void printErrorLLSD(const std::string& key, const std::string& message); + EResult mStatusCode; +}; + + +class LLAppAppearanceUtility : public LLApp +{ +public: + LLAppAppearanceUtility(int argc, char** argv); + virtual ~LLAppAppearanceUtility(); + + // LLApp interface. + bool init() override; + bool cleanup() override; + bool frame() override; + +private: + // Option parsing. + void verifyNoProcess(); + void parseArguments(); + void validateArguments(); + void initializeIO(); +public: + void usage(std::ostream& ostr); + bool isDebugMode() const { return mDebugMode; } + S32 bakeTextureSize() const { return mBakeTextureSize; } + +private: + int mArgc; + char** mArgv; + LLBakingProcess* mProcess; + std::istream* mInput; + std::ostream* mOutput; + std::string mAppName; + std::string mInputFilename; + std::string mOutputFilename; + LLUUID mAgentID; + S32 mBakeTextureSize; + bool mDebugMode; + LLTrace::Recording mRecording; + S32 mTreeMapThreshold; + std::string mTreeMapFilename; +}; + + +#endif /* LL_LLAPPAPPEARANCEUTILITY_H */ + diff --git a/indra/llappearanceutility/llbakingavatar.cpp b/indra/llappearanceutility/llbakingavatar.cpp new file mode 100644 index 00000000000..426fa705e9e --- /dev/null +++ b/indra/llappearanceutility/llbakingavatar.cpp @@ -0,0 +1,177 @@ +/** + * @File llbakingavatar.cpp + * @brief Implementation of LLBakingAvatar class which is a derivation of LLAvatarAppearance + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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$ + */ + +// linden includes +#include "linden_common.h" +#include "v3dmath.h" + +// appearance includes +#include "llavatarappearancedefines.h" + +// project includes +#include "llbakingavatar.h" +#include "llbakingjoint.h" +#include "llbakingjointmesh.h" +#include "llbakingtexlayer.h" + +using namespace LLAvatarAppearanceDefines; + +LLBakingAvatar::LLBakingAvatar(LLWearableData* wearable_data,S32 bakeTextureSize) : + LLAvatarAppearance(wearable_data), + mBakeTextureSize(bakeTextureSize) +{ +} + +// virtual +LLBakingAvatar::~LLBakingAvatar() +{ +} + +//----------------------------------------------------------------------------- +// Implemented methods +//----------------------------------------------------------------------------- + +LLAvatarJoint* LLBakingAvatar::createAvatarJoint() +{ + return new LLBakingJoint(); +} + +LLAvatarJoint* LLBakingAvatar::createAvatarJoint(S32 joint_num) +{ + return new LLBakingJoint(joint_num); +} + +LLAvatarJointMesh* LLBakingAvatar::createAvatarJointMesh() +{ + return new LLBakingJointMesh(); +} + +LLTexLayerSet* LLBakingAvatar::createTexLayerSet() +{ + return new LLBakingTexLayerSet(this); +} + +void LLBakingAvatar::bakedTextureDatasAsLLSD(LLSD& sd) const +{ + bakedtexturedata_vec_t::const_iterator baked_iter = mBakedTextureDatas.begin(); + bakedtexturedata_vec_t::const_iterator baked_end = mBakedTextureDatas.end(); + for (; baked_iter != baked_end; ++baked_iter) + { + LLBakingTexLayerSet* layer_set = dynamic_cast(baked_iter->mTexLayerSet); + LLSD layer_sd; + layer_set->asLLSD(layer_sd); + sd[LLAvatarAppearance::getDictionary()->getTexture(baked_iter->mTextureIndex)->mName] = layer_sd; + } +} + +//----------------------------------------------------------------------------- +// (Ignored) Non-implemented methods. +//----------------------------------------------------------------------------- + +void LLBakingAvatar::applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components, + LLAvatarAppearanceDefines::EBakedTextureIndex index) {} +void LLBakingAvatar::invalidateComposite(LLTexLayerSet* layerset) {} +void LLBakingAvatar::updateMeshTextures() {} +void LLBakingAvatar::dirtyMesh() {} +void LLBakingAvatar::dirtyMesh(S32 priority) {} +void LLBakingAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color) {} + +bool LLBakingAvatar::isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const +{ + return true; +} + + +//----------------------------------------------------------------------------- +// (LLERR) Non-implemented methods. +//----------------------------------------------------------------------------- + +LLVector3 LLBakingAvatar::getCharacterPosition() +{ + LL_ERRS("AppearanceUtility") << "Not implemented." << LL_ENDL; + return LLVector3::zero; +} + +LLQuaternion LLBakingAvatar::getCharacterRotation() +{ + LL_ERRS("AppearanceUtility") << "Not implemented." << LL_ENDL; + return LLQuaternion::DEFAULT; +} + +LLVector3 LLBakingAvatar::getCharacterVelocity() +{ + LL_ERRS("AppearanceUtility") << "Not implemented." << LL_ENDL; + return LLVector3::zero; +} + +LLVector3 LLBakingAvatar::getCharacterAngularVelocity() +{ + LL_ERRS("AppearanceUtility") << "Not implemented." << LL_ENDL; + return LLVector3::zero; +} + +const LLUUID& LLBakingAvatar::getID() const +{ + LL_ERRS("AppearanceUtility") << "Not implemented." << LL_ENDL; + return LLUUID::null; +} + +void LLBakingAvatar::addDebugText(const std::string& text) +{ + LL_ERRS("AppearanceUtility") << "Not implemented." << LL_ENDL; +} + +F32 LLBakingAvatar::getTimeDilation() +{ + LL_ERRS("AppearanceUtility") << "Not implemented." << LL_ENDL; + return 0.0f; +} + +void LLBakingAvatar::getGround(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm) +{ + LL_ERRS("AppearanceUtility") << "Not implemented." << LL_ENDL; +} + +F32 LLBakingAvatar::getPixelArea() const +{ + LL_ERRS("AppearanceUtility") << "Not implemented." << LL_ENDL; + return 0.0f; +} + +LLVector3d LLBakingAvatar::getPosGlobalFromAgent(const LLVector3 &position) +{ + LL_ERRS("AppearanceUtility") << "Not implemented." << LL_ENDL; + return LLVector3d::zero; +} + +LLVector3 LLBakingAvatar::getPosAgentFromGlobal(const LLVector3d &position) +{ + LL_ERRS("AppearanceUtility") << "Not implemented." << LL_ENDL; + return LLVector3::zero; +} + + + diff --git a/indra/llappearanceutility/llbakingavatar.h b/indra/llappearanceutility/llbakingavatar.h new file mode 100644 index 00000000000..8261dfc8147 --- /dev/null +++ b/indra/llappearanceutility/llbakingavatar.h @@ -0,0 +1,139 @@ +/** + * @file llbakingavatar.h + * @brief Declaration of LLBakingAvatar class which is a derivation of LLAvatarAppearance + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLBAKINGAVATAR_H +#define LL_LLBAKINGAVATAR_H + +#include "llavatarappearance.h" + +class LLBakingAvatar : public LLAvatarAppearance +{ + LOG_CLASS(LLBakingAvatar); + +/******************************************************************************** + ** ** + ** INITIALIZATION + **/ +public: + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + + LLBakingAvatar(LLWearableData* wearable_data, S32 bakeTextureSize = 512); + virtual ~LLBakingAvatar(); + + static void initClass(); // initializes static members + +/** Initialization + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** INHERITED + **/ + + //-------------------------------------------------------------------- + // LLCharacter interface + //-------------------------------------------------------------------- +public: + LLVector3 getCharacterPosition() override; + LLQuaternion getCharacterRotation() override; + LLVector3 getCharacterVelocity() override; + LLVector3 getCharacterAngularVelocity() override; + + const LLUUID& getID() const override; + void addDebugText(const std::string& text) override; + F32 getTimeDilation() override; + void getGround(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm) override; + F32 getPixelArea() const override; + LLVector3d getPosGlobalFromAgent(const LLVector3 &position) override; + LLVector3 getPosAgentFromGlobal(const LLVector3d &position) override; + + //-------------------------------------------------------------------- + // LLAvatarAppearance interface + //-------------------------------------------------------------------- +public: + void applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components, + LLAvatarAppearanceDefines::EBakedTextureIndex index) override; + void invalidateComposite(LLTexLayerSet* layerset) override; + void updateMeshTextures() override; + void dirtyMesh() override; // Dirty the avatar mesh + void onGlobalColorChanged(const LLTexGlobalColor* global_color) override; + bool isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index = 0) const override; + bool isUsingLocalAppearance() const override { return false; } + bool isEditingAppearance() const override { return false; } +private: + void dirtyMesh(S32 priority) override; // Dirty the avatar mesh, with priority + + // LLAvatarAppearance instance factories: +protected: + LLAvatarJoint* createAvatarJoint() override; + LLAvatarJoint* createAvatarJoint(S32 joint_num) override; + LLAvatarJointMesh* createAvatarJointMesh() override; + LLTexLayerSet* createTexLayerSet() override; + + +/** Inherited + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** STATE + **/ +public: + bool isSelf() const override { return true; } + bool isValid() const override { return true; } + +/** State + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** BAKING + **/ +public: + void bakedTextureDatasAsLLSD(LLSD& sd) const; + S32 bakeTextureSize() const { return mBakeTextureSize; } + +/** Baking + ** ** + *******************************************************************************/ + +private: + S32 mBakeTextureSize; +}; + +#endif /* LL_LLBAKINGAVATAR_H */ + diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h b/indra/llappearanceutility/llbakingjoint.cpp similarity index 56% rename from indra/media_plugins/gstreamer010/llmediaimplgstreamer.h rename to indra/llappearanceutility/llbakingjoint.cpp index cae11a5cb31..25edaa645f0 100644 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h +++ b/indra/llappearanceutility/llbakingjoint.cpp @@ -1,12 +1,10 @@ /** - * @file llmediaimplgstreamer.h - * @author Tofu Linden - * @brief implementation that supports media playback via GStreamer. + * @file llbakingjoint.cpp + * @brief Implementation of LLBakingJoint class * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2012, 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 @@ -24,30 +22,33 @@ * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ - * @endcond */ -// header guard -#ifndef llmediaimplgstreamer_h -#define llmediaimplgstreamer_h -#if LL_GSTREAMER010_ENABLED +#include "linden_common.h" -extern "C" { -#include -#include +#include "llbakingjoint.h" -#include "apr_pools.h" -#include "apr_dso.h" + +LLBakingJoint::LLBakingJoint() : + LLAvatarJoint() +{ } +LLBakingJoint::LLBakingJoint(S32 joint_num) : + LLAvatarJoint(joint_num) +{ +} -extern "C" { -gboolean llmediaimplgstreamer_bus_callback (GstBus *bus, - GstMessage *message, - gpointer data); +// virtual +LLBakingJoint::~LLBakingJoint() +{ } -#endif // LL_GSTREAMER010_ENABLED +// virtual +U32 LLBakingJoint::render( F32 pixelArea, bool first_pass, bool is_dummy) +{ + LL_ERRS() << "LLBakingJoint::render() should never be called!" << LL_ENDL; + return 0; +} -#endif // llmediaimplgstreamer_h diff --git a/indra/llappearanceutility/llbakingjoint.h b/indra/llappearanceutility/llbakingjoint.h new file mode 100644 index 00000000000..07e15a1d047 --- /dev/null +++ b/indra/llappearanceutility/llbakingjoint.h @@ -0,0 +1,44 @@ +/** + * @file llbakingjoint.h + * @brief Declaration of LLBakingJoint class + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLBAKINGJOINT_H +#define LL_LLBAKINGJOINT_H + +#include "llavatarjoint.h" + +class LLBakingJoint : public virtual LLAvatarJoint +{ +public: + LLBakingJoint(); + LLBakingJoint(S32 joint_num); + virtual ~LLBakingJoint(); + + // LLViewerJoint interface + U32 render( F32 pixelArea, bool first_pass = true, bool is_dummy = false ) override; +}; + +#endif /* LL_LLBAKINGJOINT_H */ + diff --git a/indra/llappearanceutility/llbakingjointmesh.cpp b/indra/llappearanceutility/llbakingjointmesh.cpp new file mode 100644 index 00000000000..b8e3283df2e --- /dev/null +++ b/indra/llappearanceutility/llbakingjointmesh.cpp @@ -0,0 +1,43 @@ +/** + * @file llbakingjointmesh.cpp + * @brief Implementation of LLBakingJointMesh class + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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 "llbakingjointmesh.h" + + +LLBakingJointMesh::LLBakingJointMesh() : + LLAvatarJointMesh() +{ +} + +// virtual +LLBakingJointMesh::~LLBakingJointMesh() +{ +} + + diff --git a/indra/llappearanceutility/llbakingjointmesh.h b/indra/llappearanceutility/llbakingjointmesh.h new file mode 100644 index 00000000000..a66bf3f61b3 --- /dev/null +++ b/indra/llappearanceutility/llbakingjointmesh.h @@ -0,0 +1,45 @@ +/** + * @file llbakingjoint.h + * @brief Implementation of LLBakingJointMesh class + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLBAKINGJOINTMESH_H +#define LL_LLBAKINGJOINTMESH_H + +#include "llavatarjointmesh.h" +#include "llbakingjoint.h" + +class LLBakingJointMesh : public LLAvatarJointMesh, public LLBakingJoint +{ +public: + LLBakingJointMesh(); + LLBakingJointMesh(S32 joint_num); + virtual ~LLBakingJointMesh(); + + U32 render( F32 pixelArea, bool first_pass = true, bool is_dummy = false ) + { return LLBakingJoint::render(pixelArea,first_pass,is_dummy); } +}; + +#endif /* LL_LLBAKINGJOINTMESH_H */ + diff --git a/indra/llappearanceutility/llbakingprocess.cpp b/indra/llappearanceutility/llbakingprocess.cpp new file mode 100644 index 00000000000..85553b0fdb3 --- /dev/null +++ b/indra/llappearanceutility/llbakingprocess.cpp @@ -0,0 +1,47 @@ +/** + * @file llbakingprocess.cpp + * @brief Implementation of LLBakingProcess class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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$ + */ + +// linden includes +#include "linden_common.h" + +#include "llsd.h" +#include "llsdserialize.h" + +// project includes +#include "llappappearanceutility.h" +#include "llbakingprocess.h" + +// virtual +void LLBakingProcess::parseInput(std::istream& input) +{ + LLSDSerialize::fromXML( mInputData, input ); + if (mInputData.isUndefined()) + { + throw LLAppException(RV_UNABLE_TO_PARSE); + } +} + + diff --git a/indra/llappearanceutility/llbakingprocess.h b/indra/llappearanceutility/llbakingprocess.h new file mode 100644 index 00000000000..de38b7a36b4 --- /dev/null +++ b/indra/llappearanceutility/llbakingprocess.h @@ -0,0 +1,60 @@ +/** + * @file llbakingprocess.h + * @brief Declaration of LLBakingProcess interface. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLBAKINGPROCESS_H +#define LL_LLBAKINGPROCESS_H + +#include + +class LLAppAppearanceUtility; +class LLSD; + +// Simple wrapper for various process modes. +class LLBakingProcess +{ +private: + // Hide default constructor. + LLBakingProcess() {} +public: + LLBakingProcess(LLAppAppearanceUtility* app) : + mApp(app) {} + virtual ~LLBakingProcess() {} + + virtual void parseInput(std::istream& input); + //virtual std::string getProcessName() const = 0; + virtual void process(std::ostream& output) = 0; + + virtual void init() {} + virtual void cleanup() {} + +protected: + LLAppAppearanceUtility* mApp; + LLSD mInputData; +}; + + +#endif /* LL_LLBAKINGPROCESS_H */ + diff --git a/indra/llappearanceutility/llbakingshadermgr.cpp b/indra/llappearanceutility/llbakingshadermgr.cpp new file mode 100644 index 00000000000..07c747a8a05 --- /dev/null +++ b/indra/llappearanceutility/llbakingshadermgr.cpp @@ -0,0 +1,250 @@ + +/** + * @file LLBakingShaderMgr.cpp + * @brief Viewer shader manager implementation. + * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#include "linden_common.h" + +#include "llbakingshadermgr.h" + +#include "lldir.h" +#include "llfile.h" +#include "llrender.h" +#include "llvertexbuffer.h" + +#if LL_DARWIN +#include "OpenGL/OpenGL.h" +#endif + +#ifdef LL_RELEASE_FOR_DOWNLOAD +#define UNIFORM_ERRS LL_WARNS_ONCE("Shader") +#else +#define UNIFORM_ERRS LL_ERRS("Shader") +#endif + +// Lots of STL stuff in here, using namespace std to keep things more readable +using std::vector; +using std::pair; +using std::make_pair; +using std::string; + +bool LLBakingShaderMgr::sInitialized = false; +bool LLBakingShaderMgr::sSkipReload = false; + +//utility shaders +LLGLSLShader gAlphaMaskProgram; + + +LLBakingShaderMgr::LLBakingShaderMgr() : + mVertexShaderLevel(SHADER_COUNT, 0), + mMaxAvatarShaderLevel(0) +{ +} + +LLBakingShaderMgr::~LLBakingShaderMgr() +{ + mVertexShaderLevel.clear(); + mShaderList.clear(); +} + +// static +LLBakingShaderMgr * LLBakingShaderMgr::instance() +{ + if(nullptr == sInstance) + { + sInstance = new LLBakingShaderMgr(); + } + + return static_cast(sInstance); +} + +void LLBakingShaderMgr::initAttribsAndUniforms(void) +{ + if (mReservedAttribs.empty()) + { + LLShaderMgr::initAttribsAndUniforms(); + } +} + + +//============================================================================ +// Set Levels + +S32 LLBakingShaderMgr::getVertexShaderLevel(S32 type) +{ + return mVertexShaderLevel[type]; +} + +//============================================================================ +// Shader Management + +void LLBakingShaderMgr::setShaders() +{ + //setShaders might be called redundantly by gSavedSettings, so return on reentrance + static bool reentrance = false; + + if (!sInitialized || reentrance || sSkipReload) + { + return; + } + + LLGLSLShader::sIndexedTextureChannels = llmax(gGLManager.mNumTextureImageUnits, 1); + + //NEVER use more than 16 texture channels (work around for prevalent driver bug) + LLGLSLShader::sIndexedTextureChannels = llmin(LLGLSLShader::sIndexedTextureChannels, 16); + + if (gGLManager.mGLSLVersionMajor < 1 || + (gGLManager.mGLSLVersionMajor == 1 && gGLManager.mGLSLVersionMinor <= 20)) + { //NEVER use indexed texture rendering when GLSL version is 1.20 or earlier + LLGLSLShader::sIndexedTextureChannels = 1; + } + + reentrance = true; + + initAttribsAndUniforms(); + + // Shaders + LL_INFOS("ShaderLoading") << "\n~~~~~~~~~~~~~~~~~~\n Loading Shaders:\n~~~~~~~~~~~~~~~~~~" << LL_ENDL; + LL_INFOS("ShaderLoading") << llformat("Using GLSL %d.%d", gGLManager.mGLSLVersionMajor, gGLManager.mGLSLVersionMinor) << LL_ENDL; + + for (S32 i = 0; i < SHADER_COUNT; i++) + { + mVertexShaderLevel[i] = 0; + } + mMaxAvatarShaderLevel = 0; + + LLVertexBuffer::unbind(); + bool loaded = false; + if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 10) + { + S32 light_class = 2; + mVertexShaderLevel[SHADER_INTERFACE] = light_class; + + // loadBasicShaders + vector< pair > shaders; + if (gGLManager.mGLSLVersionMajor >= 2 || gGLManager.mGLSLVersionMinor >= 30) + { + shaders.push_back( make_pair( "objects/indexedTextureV.glsl", 1 ) ); + } + shaders.push_back( make_pair( "objects/nonindexedTextureV.glsl", 1 ) ); + shaders.push_back( make_pair( "deferred/textureUtilV.glsl", 1 ) ); + loaded = true; + for (U32 i = 0; i < shaders.size(); i++) + { + // Note usage of GL_VERTEX_SHADER_ARB + if (loadShaderFile(shaders[i].first, shaders[i].second, GL_VERTEX_SHADER_ARB) == 0) + { + LL_WARNS("Shader") << "Failed to load vertex shader " << shaders[i].first << LL_ENDL; + loaded = false; + break; + } + } + + shaders.clear(); + + // fragment shaders + shaders.push_back( make_pair( "deferred/globalF.glsl", 1 ) ); + + for (U32 i = 0; i < shaders.size(); i++) + { + // Note usage of GL_FRAGMENT_SHADER + if (loadShaderFile(shaders[i].first, shaders[i].second, GL_FRAGMENT_SHADER_ARB) == 0) + { + LL_WARNS("Shader") << "Failed to load fragment shader " << shaders[i].first << LL_ENDL; + loaded = false; + break; + } + } + + if (loaded) + { + loaded = loadShadersInterface(); + } + } + + if (!loaded) + { + //gPipeline.mVertexShadersEnabled = false; + //gPipeline.mVertexShadersLoaded = 0; + mVertexShaderLevel[SHADER_LIGHTING] = 0; + mVertexShaderLevel[SHADER_INTERFACE] = 0; + mVertexShaderLevel[SHADER_ENVIRONMENT] = 0; + mVertexShaderLevel[SHADER_WATER] = 0; + mVertexShaderLevel[SHADER_OBJECT] = 0; + mVertexShaderLevel[SHADER_EFFECT] = 0; + mVertexShaderLevel[SHADER_WINDLIGHT] = 0; + mVertexShaderLevel[SHADER_AVATAR] = 0; + } + + //gPipeline.createGLBuffers(); + + reentrance = false; +} + +void LLBakingShaderMgr::unloadShaders() +{ + gAlphaMaskProgram.unload(); + + mVertexShaderLevel[SHADER_INTERFACE] = 0; + + //gPipeline.mVertexShadersLoaded = 0; +} + +bool LLBakingShaderMgr::loadShadersInterface() +{ + gAlphaMaskProgram.mName = "Alpha Mask Shader"; + gAlphaMaskProgram.mShaderFiles.clear(); + gAlphaMaskProgram.mShaderFiles.push_back(make_pair("interface/alphamaskV.glsl", GL_VERTEX_SHADER_ARB)); + gAlphaMaskProgram.mShaderFiles.push_back(make_pair("interface/alphamaskF.glsl", GL_FRAGMENT_SHADER_ARB)); + gAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + + if( !gAlphaMaskProgram.createShader() ) + { + mVertexShaderLevel[SHADER_INTERFACE] = 0; + return false; + } + + return true; +} + +std::string LLBakingShaderMgr::getShaderDirPrefix(void) +{ + return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "shaders/class"); +} + +void LLBakingShaderMgr::updateShaderUniforms(LLGLSLShader * shader) +{ +} + +LLBakingShaderMgr::shader_iter LLBakingShaderMgr::beginShaders() const +{ + return mShaderList.begin(); +} + +LLBakingShaderMgr::shader_iter LLBakingShaderMgr::endShaders() const +{ + return mShaderList.end(); +} diff --git a/indra/llappearanceutility/llbakingshadermgr.h b/indra/llappearanceutility/llbakingshadermgr.h new file mode 100644 index 00000000000..60ab3f94e8d --- /dev/null +++ b/indra/llappearanceutility/llbakingshadermgr.h @@ -0,0 +1,137 @@ +/** + * @file llbakingshadermgr.h + * @brief Texture Baking Shader Manager + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_BAKING_SHADER_MGR_H +#define LL_BAKING_SHADER_MGR_H + +#include "llshadermgr.h" + +class LLBakingShaderMgr: public LLShaderMgr +{ +public: + static bool sInitialized; + static bool sSkipReload; + + LLBakingShaderMgr(); + ~LLBakingShaderMgr(); + + // singleton pattern implementation + static LLBakingShaderMgr * instance(); + + void initAttribsAndUniforms(void) override; + void setShaders(); + void unloadShaders(); + S32 getVertexShaderLevel(S32 type); + bool loadShadersInterface(); + + std::vector mVertexShaderLevel; + S32 mMaxAvatarShaderLevel; + + enum EShaderClass + { + SHADER_LIGHTING, + SHADER_OBJECT, + SHADER_AVATAR, + SHADER_ENVIRONMENT, + SHADER_INTERFACE, + SHADER_EFFECT, + SHADER_WINDLIGHT, + SHADER_WATER, + SHADER_DEFERRED, + SHADER_TRANSFORM, + SHADER_COUNT + }; + + // simple model of forward iterator + // http://www.sgi.com/tech/stl/ForwardIterator.html + class shader_iter + { + private: + friend bool operator == (shader_iter const & a, shader_iter const & b); + friend bool operator != (shader_iter const & a, shader_iter const & b); + + typedef std::vector::const_iterator base_iter_t; + public: + shader_iter() + { + } + + shader_iter(base_iter_t iter) : mIter(iter) + { + } + + LLGLSLShader & operator * () const + { + return **mIter; + } + + LLGLSLShader * operator -> () const + { + return *mIter; + } + + shader_iter & operator++ () + { + ++mIter; + return *this; + } + + shader_iter operator++ (int) + { + return mIter++; + } + + private: + base_iter_t mIter; + }; + + shader_iter beginShaders() const; + shader_iter endShaders() const; + + std::string getShaderDirPrefix(void) override; + + void updateShaderUniforms(LLGLSLShader * shader) override; + +private: + + // the list of shaders we need to propagate parameters to. + std::vector mShaderList; + +}; //LLBakingShaderMgr + +inline bool operator == (LLBakingShaderMgr::shader_iter const & a, LLBakingShaderMgr::shader_iter const & b) +{ + return a.mIter == b.mIter; +} + +inline bool operator != (LLBakingShaderMgr::shader_iter const & a, LLBakingShaderMgr::shader_iter const & b) +{ + return a.mIter != b.mIter; +} + +extern LLVector4 gShinyOrigin; + +#endif // LL_BAKING_SHADER_MGR_H diff --git a/indra/llappearanceutility/llbakingtexlayer.cpp b/indra/llappearanceutility/llbakingtexlayer.cpp new file mode 100644 index 00000000000..3427331a964 --- /dev/null +++ b/indra/llappearanceutility/llbakingtexlayer.cpp @@ -0,0 +1,373 @@ +/** + * @file llbakingtexlayer.cpp + * @brief Implementation of LLBakingTexLayer class + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "indra_constants.h" +#include "llappappearanceutility.h" +#include "llavatarappearance.h" +#include "llbakingtexlayer.h" +#include "llbakingwearable.h" +#include "llfasttimer.h" +#include "lllocaltextureobject.h" +#include "llimagej2c.h" +#include "llwearabledata.h" +#include "llmd5.h" +#include "llbakingavatar.h" + +//#define DEBUG_TEXTURE_IDS 1 + +static const char* BAKE_HASH_VERSION = "3"; + +using namespace LLAvatarAppearanceDefines; + +LLBakingTexLayerSetBuffer::LLBakingTexLayerSetBuffer(LLTexLayerSet* const owner, S32 width, S32 height) + : LLTexLayerSetBuffer(owner), + LLBakingTexture( width, height, 4 ) +{} + +// virtual +LLBakingTexLayerSetBuffer::~LLBakingTexLayerSetBuffer() +{ + destroyGLTexture(); +} + +bool LLBakingTexLayerSetBuffer::render() +{ + bool result = false; + + preRenderTexLayerSet(); + result = renderTexLayerSet(nullptr); + postRenderTexLayerSet(result); + + return result; +} + +static LLFastTimer::DeclareTimer FTM_MID_RENDER("midRenderTexLayerSet"); +static LLFastTimer::DeclareTimer FTM_CREATE_J2C("Encode J2C image."); +void LLBakingTexLayerSetBuffer::midRenderTexLayerSet(bool success) +{ + LL_RECORD_BLOCK_TIME(FTM_MID_RENDER); + if (!mTexLayerSet->isVisible()) + { + // Should have used IMG_INVISIBLE during hash id generation? + LL_ERRS() << "Rendered texture for non-visible tex layer set!" << LL_ENDL; + } + + if (!success) + { + throw LLAppException(RV_UNABLE_TO_BAKE, " Rendering process failed."); + } + + // Get the COLOR information from our texture + LL_DEBUGS() << "glReadPixels..." << LL_ENDL; + LL_DEBUGS() << "getCompositeWidth()" << getCompositeWidth() << "getCompositeHeight()" << getCompositeHeight() << LL_ENDL; + + U8* baked_color_data = new U8[ getCompositeWidth() * getCompositeHeight() * 4 ]; + glReadPixels(getCompositeOriginX(), getCompositeOriginY(), + getCompositeWidth(), getCompositeHeight(), + GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data ); + stop_glerror(); + + // Get the MASK information from our texture + LLGLSUIDefault gls_ui; + LL_DEBUGS() << "Creating baked mask image raw.." << LL_ENDL; + LLPointer baked_mask_image = new LLImageRaw(getCompositeWidth(), getCompositeHeight(), 1 ); + U8* baked_mask_data = baked_mask_image->getData(); + + LL_DEBUGS() << "Gathering Morph Mask Alpha..." << LL_ENDL; + mTexLayerSet->gatherMorphMaskAlpha(baked_mask_data, + getCompositeOriginX(), getCompositeOriginY(), + getCompositeWidth(), getCompositeHeight(), nullptr); + + // Create the baked image from our color and mask information + const S32 baked_image_components = 5; // red green blue [bump] clothing + LL_DEBUGS() << "Creating baked image raw.." << LL_ENDL; + LLPointer baked_image = new LLImageRaw( getCompositeWidth(), getCompositeHeight(), baked_image_components ); + U8* baked_image_data = baked_image->getData(); + S32 i = 0; + LL_DEBUGS() << "Running ugly loop..." << LL_ENDL; + for (S32 u=0; u < getCompositeWidth(); u++) + { + for (S32 v=0; v < getCompositeHeight(); v++) + { + baked_image_data[5*i + 0] = baked_color_data[4*i + 0]; + baked_image_data[5*i + 1] = baked_color_data[4*i + 1]; + baked_image_data[5*i + 2] = baked_color_data[4*i + 2]; + baked_image_data[5*i + 3] = baked_color_data[4*i + 3]; // alpha should be correct for eyelashes. + baked_image_data[5*i + 4] = baked_mask_data[i]; + i++; + } + } + + { + LL_RECORD_BLOCK_TIME(FTM_CREATE_J2C); + LL_DEBUGS() << "Creating J2C..." << LL_ENDL; + mCompressedImage = new LLImageJ2C; + const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask) + if (!mCompressedImage->encode(baked_image, comment_text)) + { + throw LLAppException(RV_UNABLE_TO_ENCODE); + } + } + + delete [] baked_color_data; +} + +LLBakingTexLayerSet::LLBakingTexLayerSet(LLAvatarAppearance* const appearance) : + LLTexLayerSet(appearance) +{ +} + +// virtual +LLBakingTexLayerSet::~LLBakingTexLayerSet() +{ +} + +// Ignored. +void LLBakingTexLayerSet::requestUpdate() +{ +} + +void LLBakingTexLayerSet::createComposite() +{ + if(!mComposite) + { + const LLBakingAvatar* avatar = dynamic_cast (mAvatarAppearance); + S32 width = avatar->bakeTextureSize(); + S32 height = avatar->bakeTextureSize(); + + LL_DEBUGS() << "Creating composite with width and height " << width << " " << height << LL_ENDL; + + mComposite = new LLBakingTexLayerSetBuffer(this, width, height); + } +} + +LLSD LLBakingTexLayerSet::computeTextureIDs() const +{ + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = + LLAvatarAppearance::getDictionary()->getBakedTexture(getBakedTexIndex()); +#ifdef DEBUG_TEXTURE_IDS + const std::string& slot_name = LLAvatarAppearance::getDictionary()->getTexture( + LLAvatarAppearance::getDictionary()->bakedToLocalTextureIndex(getBakedTexIndex()) )->mDefaultImageName; + const LLAvatarAppearanceDictionary::TextureEntry* entry = LLAvatarAppearance::getDictionary()->getTexture(baked_dict->mTextureIndex); + LL_DEBUGS() << "-----------------------------------------------------------------" << LL_ENDL; + LL_DEBUGS() << "BakedTexIndex = " << (S32) getBakedTexIndex() << " (" << slot_name << ") " + << "BakedEntry::mTextureIndex = " << (S32) baked_dict->mTextureIndex + << " (" << entry->mDefaultImageName + << ")" << LL_ENDL; + //LL_DEBUGS() << "LLAvatarAppearanceDictionary::getTEWearableType(" << baked_dict->mTextureIndex << ") = " << (S32) LLAvatarAppearanceDictionary::getTEWearableType(baked_dict->mTextureIndex) << LL_ENDL; + + texture_vec_t::const_iterator idx_iter = baked_dict->mLocalTextures.begin(); + texture_vec_t::const_iterator idx_end = baked_dict->mLocalTextures.end(); + std::ostringstream idx_str; + for (; idx_iter != idx_end; ++idx_iter) + { + entry = LLAvatarAppearance::getDictionary()->getTexture((*idx_iter)); + idx_str << (*idx_iter) << " (" << entry->mDefaultImageName + << ";" << LLWearableType::getInstance()->getTypeName( entry->mWearableType ) + << "), "; + } + LL_DEBUGS() << "BakedEntry::mLocalTextures: " << idx_str.str() << LL_ENDL; + wearables_vec_t::const_iterator type_iter = baked_dict->mWearables.begin(); + wearables_vec_t::const_iterator type_end = baked_dict->mWearables.end(); + std::ostringstream type_str; + for (; type_iter != type_end; ++type_iter) + { + type_str << (S32) (*type_iter) << " (" + << LLWearableType::getInstance()->getTypeName( (*type_iter) ) + << "), "; + } + LL_DEBUGS() << "BakedEntry::mWearables: " << type_str.str() << LL_ENDL; + //LL_DEBUGS() << "BakedEntry::mWearablesHashID: " << baked_dict->mWearablesHashID << LL_ENDL; +#endif + + LLMD5 hash; + std::set texture_ids; + + bool is_visible = true; + bool hash_computed = computeLayerListTextureIDs(hash, texture_ids, mLayerList, is_visible); + if (is_visible) + { + hash_computed |= computeLayerListTextureIDs(hash, texture_ids, mMaskLayerList, is_visible); + } + + LLUUID hash_id; + if (!is_visible) + { + hash_id = IMG_INVISIBLE; + texture_ids.clear(); + } + else if (hash_computed) + { + if ((getBakedTexIndex() == EBakedTextureIndex::BAKED_LEFT_ARM) || + (getBakedTexIndex() == EBakedTextureIndex::BAKED_LEFT_LEG) || + (getBakedTexIndex() == EBakedTextureIndex::BAKED_AUX1) || + (getBakedTexIndex() == EBakedTextureIndex::BAKED_AUX2) || + (getBakedTexIndex() == EBakedTextureIndex::BAKED_AUX3)) + { + hash.update(BAKE_HASH_VERSION); + } + + hash.update((const unsigned char*)baked_dict->mWearablesHashID.mData, UUID_BYTES); + hash.finalize(); + hash.raw_digest(hash_id.mData); + } + + if (hash_id.isNull()) + { + hash_id = IMG_DEFAULT_AVATAR; + } + + if (getBakedTexIndex() == EBakedTextureIndex::BAKED_SKIRT) + { + if (getAvatarAppearance()->getWearableData()->getWearableCount(LLWearableType::WT_SKIRT) == 0) + { + hash_id = IMG_DEFAULT_AVATAR; + texture_ids.clear(); + } + } + LLSD sd; + sd["hash_id"] = hash_id; + sd["texture_ids"] = LLSD::emptyArray(); + std::set::iterator id_iter = texture_ids.begin(); + std::set::iterator id_end = texture_ids.end(); + for (; id_iter != id_end; ++id_iter) + { + sd["texture_ids"].append( *id_iter ); + } + return sd; +} + +bool LLBakingTexLayerSet::computeLayerListTextureIDs(LLMD5& hash, + std::set& texture_ids, + const layer_list_t& layer_list, + bool& is_visible) const +{ + is_visible = true; + bool hash_computed = false; + layer_list_t::const_iterator iter = layer_list.begin(); + layer_list_t::const_iterator end = layer_list.end(); + for (; iter != end; ++iter) + { + const LLTexLayerInterface* layer_template = *iter; + LLWearableType::EType wearable_type = layer_template->getWearableType(); + ETextureIndex te = layer_template->getLocalTextureIndex(); + U32 num_wearables = getAvatarAppearance()->getWearableData()->getWearableCount(wearable_type); +#ifdef DEBUG_TEXTURE_IDS + const LLAvatarAppearanceDictionary::TextureEntry* entry = LLAvatarAppearance::getDictionary()->getTexture(te); + if (entry) + { + LL_DEBUGS() << "LLTexLayerInterface(" << layer_template->getName() << ") type = " + << (S32) wearable_type << " (" + << LLWearableType::getInstance()->getTypeName( wearable_type ) << ") te = " + << (S32) te << " ("<< entry->mDefaultImageName + << ";" << LLWearableType::getInstance()->getTypeName( entry->mWearableType ) + << ") wearable_count = " << num_wearables << LL_ENDL; + } + else + { + LL_DEBUGS() << "LLTexLayerInterface(" << layer_template->getName() << ") type = " + << (S32) wearable_type << " (" + << LLWearableType::getInstance()->getTypeName( wearable_type ) + << ") wearable_count = " << num_wearables << LL_ENDL; + } +#endif + if (LLWearableType::WT_INVALID == wearable_type) + { + //LL_DEBUGS() << "Skipping invalid wearable type" << LL_ENDL; + continue; + } + + for (U32 i = 0; i < num_wearables; i++) + { + LLBakingWearable* wearable = dynamic_cast ( + getAvatarAppearance()->getWearableData()->getWearable(wearable_type, i)); + if (!wearable) + { + //LL_DEBUGS() << "Skipping wearable" << LL_ENDL; + continue; + } +#ifdef DEBUG_TEXTURE_IDS + S32 num_ltos = wearable->getLocalTextureListSeq().size(); + LL_DEBUGS() << "LLWearable (" << wearable->getName() << ") type = " + << (S32) wearable->getAssetType() << " (" + << LLAssetType::lookup(wearable->getAssetType()) + << ") num_ltos = " << num_ltos << LL_ENDL; +#endif + LLLocalTextureObject *lto = wearable->getLocalTextureObject(te); + if (lto) + { +#ifdef DEBUG_TEXTURE_IDS + LL_DEBUGS() << "LocalTextureObject id = " << lto->getID() << " num texlayers = " << lto->getNumTexLayers() << LL_ENDL; +#endif + // Hash texture id + LLUUID texture_id = lto->getID(); + if (IMG_INVISIBLE == texture_id) + { + is_visible = false; + } + hash.update((const unsigned char*)texture_id.mData, UUID_BYTES); + hash_computed = true; + // Add texture to list. + texture_ids.insert(texture_id); + } +#ifdef DEBUG_TEXTURE_IDS + else + { + LL_DEBUGS() << "LLWearable -- no LocalTextureObject for te " << (S32) te << LL_ENDL; + } + + + for(S32 i = 0; i < (S32)TEX_NUM_INDICES; i++) + { + lto = wearable->getLocalTextureObject(i); + if (lto) + { + LL_DEBUGS() << "LTO (" << i << ") id = " << lto->getID() << " num texlayers = " << lto->getNumTexLayers() << LL_ENDL; + } + } +#endif + + for( LLVisualParam* param = getAvatarAppearance()->getFirstVisualParam(); + param; param = getAvatarAppearance()->getNextVisualParam() ) + { + // cross-wearable parameters are not authoritative, as they are driven by a different wearable. + if( (((LLViewerVisualParam*)param)->getWearableType() == wearable_type) && + (!((LLViewerVisualParam*)param)->getCrossWearable()) ) + { + std::ostringstream ostr; + F32 weight = wearable->getVisualParamWeight(param->getID()); + ostr << param->getID() << " " << weight; + hash.update(ostr.str()); + hash_computed = true; + } + } + } + } + return hash_computed; +} + diff --git a/indra/llappearanceutility/llbakingtexlayer.h b/indra/llappearanceutility/llbakingtexlayer.h new file mode 100644 index 00000000000..dc82b27ce22 --- /dev/null +++ b/indra/llappearanceutility/llbakingtexlayer.h @@ -0,0 +1,77 @@ +/** + * @file llbakingtexlayer.h + * @brief Declaration of LLBakingTexLayerSet. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLBAKINGTEXLAYER_H +#define LL_LLBAKINGTEXLAYER_H + +#include "llbakingtexture.h" +#include "llimagej2c.h" +#include "llpointer.h" +#include "lltexlayer.h" + +class LLMD5; + +class LLBakingTexLayerSetBuffer : public LLTexLayerSetBuffer, public LLBakingTexture +{ + LOG_CLASS(LLBakingTexLayerSetBuffer); +public: + LLBakingTexLayerSetBuffer(LLTexLayerSet* const owner, S32 width, S32 height); + virtual ~LLBakingTexLayerSetBuffer(); + + LLImageJ2C* getCompressedImage() { return mCompressedImage; } + + bool render(); + bool bindDebugImage(const S32 stage = 0) override { return false; } + bool isActiveFetching() override { return false; }; + +private: + S32 getCompositeOriginX() const override { return 0; } + S32 getCompositeOriginY() const override { return 0; } + S32 getCompositeWidth() const override { return getFullWidth(); } + S32 getCompositeHeight() const override { return getFullHeight(); } + void midRenderTexLayerSet(bool success) override; + + LLPointer mCompressedImage; +}; + +class LLBakingTexLayerSet : public LLTexLayerSet +{ +public: + LLBakingTexLayerSet(LLAvatarAppearance* const appearance); + virtual ~LLBakingTexLayerSet(); + + LLSD computeTextureIDs() const; + bool computeLayerListTextureIDs(LLMD5& hash, + std::set& texture_ids, + const layer_list_t& layer_list, + bool& is_visible) const; + + void requestUpdate() override; + void createComposite() override; +}; + +#endif /* LL_LLBAKINGTEXLAYER_H */ + diff --git a/indra/llappearanceutility/llbakingtexture.cpp b/indra/llappearanceutility/llbakingtexture.cpp new file mode 100644 index 00000000000..ae83081aefe --- /dev/null +++ b/indra/llappearanceutility/llbakingtexture.cpp @@ -0,0 +1,81 @@ +/** + * @file llbakingtexture.cpp + * @brief Implementation of LLBakingTexture class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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$ + */ + +// linden includes +#include "linden_common.h" + +// project includes +#include "llbakingtexture.h" +#include "llgltexture.h" +#include "llimage.h" + +static const bool USE_MIP_MAPS = true; + +LLBakingTexture::LLBakingTexture(const LLUUID& id, const LLImageRaw* raw) + : LLGLTexture(raw, USE_MIP_MAPS), + mID(id) +{ +} + +LLBakingTexture::LLBakingTexture(bool usemipmaps) + : LLGLTexture(usemipmaps), + mID(LLUUID::null) +{ +} + +LLBakingTexture::LLBakingTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps) + : LLGLTexture(width, height, components, USE_MIP_MAPS), + mID(LLUUID::null) +{ +} + +// virtual +LLBakingTexture::~LLBakingTexture() +{ +} + +void LLBakingTexture::setKnownDrawSize(S32 width, S32 height) +{ + //nothing here. + LL_ERRS() << "Not implemented." << LL_ENDL; +} + +bool LLBakingTexture::bindDefaultImage(S32 stage) +{ + LL_ERRS() << "Not implemented." << LL_ENDL; + return false; +} + +void LLBakingTexture::forceImmediateUpdate() +{ + LL_ERRS() << "Not implemented." << LL_ENDL; +} + +void LLBakingTexture::updateBindStatsForTester() +{ + LL_ERRS() << "Not implemented." << LL_ENDL; +} + diff --git a/indra/llappearanceutility/llbakingtexture.h b/indra/llappearanceutility/llbakingtexture.h new file mode 100644 index 00000000000..50b4193b2ee --- /dev/null +++ b/indra/llappearanceutility/llbakingtexture.h @@ -0,0 +1,69 @@ +/** + * @file llbakingtexture.h + * @brief Declaration of LLBakingTexture class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLBAKINGTEXTURE_H +#define LL_LLBAKINGTEXTURE_H + +#include "llgltexture.h" +#include "lluuid.h" + +class LLImageRaw; + +class LLBakingTexture : public LLGLTexture +{ +public: + enum + { + LOCAL_TEXTURE, + BAKING_TEXTURE, + INVALID_TEXTURE_TYPE + }; + LLBakingTexture(const LLUUID& id, const LLImageRaw* raw); + LLBakingTexture(bool usemipmaps); + LLBakingTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps = true); + const LLUUID& getID() const override { return mID; } + S8 getType() const override { return BAKING_TEXTURE; } + + // Not implemented. + void setKnownDrawSize(S32 width, S32 height) override; + bool bindDefaultImage(const S32 stage = 0) override ; + void forceImmediateUpdate() override; + void updateBindStatsForTester() override ; + bool bindDebugImage(const S32 stage = 0) override { return false; } + bool isActiveFetching() override { return false; } + +protected: + virtual ~LLBakingTexture(); + LOG_CLASS(LLBakingTexture); +private: + // Hide default constructor. + LLBakingTexture() {} + + LLUUID mID; +}; + +#endif /* LL_LLBAKINGTEXTURE_H */ + diff --git a/indra/llappearanceutility/llbakingwearable.cpp b/indra/llappearanceutility/llbakingwearable.cpp new file mode 100644 index 00000000000..0e5251aba1a --- /dev/null +++ b/indra/llappearanceutility/llbakingwearable.cpp @@ -0,0 +1,77 @@ +/** + * @file llbakingwearable.cpp + * @brief Implementation of LLBakingWearable class + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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 "llavatarappearance.h" +#include "llavatarappearancedefines.h" +#include "llbakingwearable.h" +#include "llmd5.h" +#include "indra_constants.h" + +using namespace LLAvatarAppearanceDefines; + +LLBakingWearable::LLBakingWearable() +{ +} + +// virtual +LLBakingWearable::~LLBakingWearable() +{ +} + +// virtual +void LLBakingWearable::setUpdated() const +{ +} + +// virtual +void LLBakingWearable::addToBakedTextureHash(LLMD5& hash) const +{ +} + +// virtual +LLUUID LLBakingWearable::getDefaultTextureImageID(ETextureIndex index) const +{ + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearance::getDictionary()->getTexture(index); + const std::string &default_image_name = texture_dict->mDefaultImageName; + if (default_image_name == "") + { + return IMG_DEFAULT_AVATAR; + } + else + { + //return LLUUID(gSavedSettings.getString(default_image_name)); + // *TODO: Fix this. + return LLUUID::null; + } +} + +void LLBakingWearable::asLLSD(LLSD& sd) const +{ + // stub implementation. TODO: fill in. +} diff --git a/indra/llappearanceutility/llbakingwearable.h b/indra/llappearanceutility/llbakingwearable.h new file mode 100644 index 00000000000..bb96dc37099 --- /dev/null +++ b/indra/llappearanceutility/llbakingwearable.h @@ -0,0 +1,48 @@ +/** + * @file llbakingwearable.h + * @brief Declaration of LLBakingWearable class + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLBAKINGWEARABLE_H +#define LL_LLBAKINGWEARABLE_H + +#include "llwearable.h" +#include "llmd5.h" + +class LLBakingWearable : public LLWearable +{ +public: + LLBakingWearable(); + virtual ~LLBakingWearable(); + + virtual void setUpdated() const; + virtual void addToBakedTextureHash(LLMD5& hash) const; + virtual LLUUID getDefaultTextureImageID(LLAvatarAppearanceDefines::ETextureIndex index) const; + + void asLLSD(LLSD& sd) const; + +}; + +#endif /* LL_LLBAKINGWEARABLE_H */ + diff --git a/indra/llappearanceutility/llbakingwearablesdata.cpp b/indra/llappearanceutility/llbakingwearablesdata.cpp new file mode 100644 index 00000000000..18edb863480 --- /dev/null +++ b/indra/llappearanceutility/llbakingwearablesdata.cpp @@ -0,0 +1,131 @@ +/** + * @file llbakingwearablesdata.cpp + * @brief Implementation of LLBakingWearablesData class + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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 "llbakingwearablesdata.h" +#include "llbakingwearable.h" + +using namespace LLAvatarAppearanceDefines; + +LLBakingWearablesData::LLBakingWearablesData() +{ +} + +// virtual +LLBakingWearablesData::~LLBakingWearablesData() +{ + std::for_each(mWearables.begin(), mWearables.end(), DeletePointer()); + mWearables.clear(); +} + +void LLBakingWearablesData::setWearableOutfit(LLSD& sd) +{ + LLSD::array_const_iterator type_iter = sd.beginArray(); + LLSD::array_const_iterator type_end = sd.endArray(); + S32 wearable_index = 0; + for (; type_iter != type_end && wearable_index < (S32) LLWearableType::WT_COUNT; ++type_iter, ++wearable_index) + { + LLSD::array_const_iterator wearable_iter = type_iter->beginArray(); + LLSD::array_const_iterator wearable_end = type_iter->endArray(); + for (; wearable_iter != wearable_end; ++wearable_iter) + { + if ( wearable_iter->isDefined() ) + { + LLBakingWearable* wearable = new LLBakingWearable(); + std::istringstream istr( (*wearable_iter)["contents"].asString() ); + wearable->importStream(istr, mAvatarAppearance); + + // Sanity check the wearable type. + if (wearable->getType() != wearable_index) + { + LL_WARNS() << "Unexpected wearable type! Expected " << wearable_index + << ", processed " << (S32) wearable->getType() << LL_ENDL; + // *TODO: Throw exception? + delete wearable; + continue; + } + mWearables.push_back(wearable); + + const LLWearableType::EType type = wearable->getType(); + if (wearable->getAssetType() == LLAssetType::AT_BODYPART) + { + // exactly one wearable per body part + setWearable(type,0,wearable); + } + else + { + pushWearable(type,wearable); + } + } + } + } + + wearable_list_t::const_iterator wearable_iter = mWearables.begin(); + wearable_list_t::const_iterator wearable_end = mWearables.end(); + for (; wearable_iter != wearable_end; ++wearable_iter) + { + LLBakingWearable* wearable = (*wearable_iter); + const bool removed = false; + wearableUpdated(wearable, removed); + } + + for(wearable_index = 0; wearable_index < (S32) LLWearableType::WT_COUNT; wearable_index++) + { + LLWearable* top_wearable = getTopWearable((LLWearableType::EType)wearable_index); + if (top_wearable) + { + top_wearable->writeToAvatar(mAvatarAppearance); + } + } +} + + +void LLBakingWearablesData::asLLSD(LLSD& sd) const +{ + sd = LLSD::emptyMap(); + wearableentry_map_t::const_iterator type_iter = mWearableDatas.begin(); + wearableentry_map_t::const_iterator type_end = mWearableDatas.end(); + for (; type_iter != type_end; ++type_iter) + { + LLSD wearable_type_sd = LLSD::emptyArray(); + LLWearableType::EType wearable_type = type_iter->first; + wearableentry_vec_t::const_iterator wearable_iter = type_iter->second.begin(); + wearableentry_vec_t::const_iterator wearable_end = type_iter->second.end(); + for (; wearable_iter != wearable_end; ++wearable_iter) + { + const LLBakingWearable* wearable = dynamic_cast(*wearable_iter); + LLSD wearable_sd; + wearable->asLLSD(wearable_sd); + wearable_type_sd.append(wearable_sd); + } + sd[LLWearableType::getInstance()->getTypeName(wearable_type)] = wearable_type_sd; + } +} + + + diff --git a/indra/llappearanceutility/llbakingwearablesdata.h b/indra/llappearanceutility/llbakingwearablesdata.h new file mode 100644 index 00000000000..1db2ca4bc12 --- /dev/null +++ b/indra/llappearanceutility/llbakingwearablesdata.h @@ -0,0 +1,55 @@ +/** + * @file llbakingwearablesdata.h + * @brief Declaration of LLBakingWearablesData class + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLBAKINGWEARABLESDATA_H +#define LL_LLBAKINGWEARABLESDATA_H + +#include "llwearabledata.h" + +class LLBakingWearable; + +class LLBakingWearablesData : public LLWearableData +{ +public: + LLBakingWearablesData(); + virtual ~LLBakingWearablesData(); + + void setWearableOutfit(LLSD& sd); + + //-------------------------------------------------------------------- + // I/O methods + //-------------------------------------------------------------------- +public: + void asLLSD(LLSD& sd) const; + +private: + typedef std::vector wearable_list_t; + wearable_list_t mWearables; + +}; + +#endif /* LL_LLBAKINGWEARABLESDATA_H */ + diff --git a/indra/llappearanceutility/llbakingwindow.cpp b/indra/llappearanceutility/llbakingwindow.cpp new file mode 100644 index 00000000000..87991059323 --- /dev/null +++ b/indra/llappearanceutility/llbakingwindow.cpp @@ -0,0 +1,94 @@ +/** + * @file llbakingwindow.cpp + * @brief Implementation of LLBakingWindow class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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$ + */ + +// linden includes +#include "linden_common.h" + +// project includes +#include "llappappearanceutility.h" +#include "llbakingshadermgr.h" +#include "llbakingwindow.h" +#include "llgl.h" +#include "llgltexture.h" +#include "llvertexbuffer.h" + +LLBakingWindow::LLBakingWindow(S32 width, S32 height) +{ + const S32 WINDOW_ORIGIN_X = 0; + const S32 WINDOW_ORIGIN_Y = 0; + const U32 FLAGS = 32; // *TODO: Why did mapserver use this? mFlags looks unused. + const bool NO_FULLSCREEN = false; + const bool NO_CLEAR_BG = false; + const bool NO_DISABLE_VSYNC = false; + const bool NO_IGNORE_PIXEL_DEPTH = false; + const bool USE_GL = true; + mWindow = LLWindowManager::createWindow(this, + "appearanceutility", "Appearance Utility", + WINDOW_ORIGIN_X, WINDOW_ORIGIN_Y, + width, height, + FLAGS, + NO_FULLSCREEN, + NO_CLEAR_BG, + NO_DISABLE_VSYNC, //gSavedSettings.getBOOL("DisableVerticalSync"), + USE_GL, // not headless + NO_IGNORE_PIXEL_DEPTH); //gIgnorePixelDepth = false + + if (nullptr == mWindow) + { + throw LLAppException(RV_UNABLE_TO_INIT_GL); + } + + LLVertexBuffer::initClass(mWindow); + + gGL.init(true); + + if (!LLBakingShaderMgr::sInitialized) + { //immediately initialize shaders + LLBakingShaderMgr::sInitialized = true; + LLBakingShaderMgr::instance()->setShaders(); + } + + LLImageGL::initClass(mWindow, LLGLTexture::MAX_GL_IMAGE_CATEGORY, true, false); + + // mWindow->show(); + // mWindow->bringToFront(); + // mWindow->focusClient(); + // mWindow->gatherInput(); +} + +LLBakingWindow::~LLBakingWindow() +{ + if (mWindow) + { + LLWindowManager::destroyWindow(mWindow); + } + mWindow = nullptr; +} + +void LLBakingWindow::swapBuffers() +{ + mWindow->swapBuffers(); +} diff --git a/indra/llappearanceutility/llbakingwindow.h b/indra/llappearanceutility/llbakingwindow.h new file mode 100644 index 00000000000..a6bf1d87149 --- /dev/null +++ b/indra/llappearanceutility/llbakingwindow.h @@ -0,0 +1,45 @@ +/** + * @file llbakingwindow.h + * @brief Declaration of LLBakingWindow class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLBAKINGWINDOW_H +#define LL_LLBAKINGWINDOW_H + +#include "llwindow.h" +#include "llwindowcallbacks.h" + +class LLBakingWindow : public LLWindowCallbacks +{ +public: + LLBakingWindow(S32 width, S32 height); + ~LLBakingWindow(); + + void swapBuffers(); +private: + LLWindow* mWindow; +}; + +#endif /* LL_LLBAKINGWINDOW_H */ + diff --git a/indra/llappearanceutility/llprocessparams.cpp b/indra/llappearanceutility/llprocessparams.cpp new file mode 100755 index 00000000000..ad1b44e794a --- /dev/null +++ b/indra/llappearanceutility/llprocessparams.cpp @@ -0,0 +1,281 @@ +/** + * @file llprocessparams.cpp + * @brief Implementation of LLProcessParams class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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$ + */ + +// linden includes +#include "linden_common.h" + +#include "llsd.h" +#include "llsdserialize.h" +#include "llsdutil.h" +#include "llsdutil_math.h" +#include "llstl.h" +#include "llmath.h" +#include "llquantize.h" + +// appearance includes +#include "lltexturemanagerbridge.h" +#include "llwearabletype.h" +#include "llavatarappearancedefines.h" + +// project includes +#include "llappappearanceutility.h" +#include "llbakingavatar.h" +#include "llbakingtexlayer.h" +#include "llbakingwearable.h" +#include "llbakingwearablesdata.h" +#include "llprocessparams.h" + +#define APPEARANCE_PARAM_VERSION 11000 + +const U32 FULL_RIG_JOINT_COUNT = 20; + +using namespace LLAvatarAppearanceDefines; + +// Create a bridge to the viewer texture manager. +class LLNullTextureManagerBridge : public LLTextureManagerBridge +{ +public: + LLPointer getLocalTexture(bool usemipmaps = true, bool generate_gl_tex = true) override + { + return nullptr; + } + + LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps, bool generate_gl_tex = true) override + { + return nullptr; + } + + LLGLTexture* getFetchedTexture(const LLUUID &image_id) override + { + return nullptr; + } +}; + +LLSD dump_joint_offsets_for_avatar(LLBakingAvatar& avatar) +{ + LLSD joints = LLSD::emptyArray(); + + for (U32 joint_index = 0;; joint_index++) + { + LLJoint* pJoint = avatar.getCharacterJoint(joint_index); + if (!pJoint) + { + break; + } + LLVector3 pos; + LLUUID mesh_id; + if (pJoint->hasAttachmentPosOverride(pos, mesh_id)) + { + LLSD info; + info["name"] = pJoint->getName(); + info["pos"] = ll_sd_from_vector3(pos); + info["mesh_id"] = mesh_id; + joints.append(info); + } + } + + return joints; +} + +void LLProcessParams::process(std::ostream& output) +{ + if (!mInputData.has("wearables")) throw LLAppException(RV_UNABLE_TO_PARSE, " Missing wearables"); + + // Create a null-texture manager bridge. + gTextureManagerBridgep = new LLNullTextureManagerBridge(); + + // Construct the avatar. + LLBakingWearablesData wearable_data; + LLBakingAvatar avatar(&wearable_data, mApp->bakeTextureSize()); + avatar.initInstance(); + wearable_data.setAvatarAppearance(&avatar); + + //Process the params data for joint information + //bool bodySizeSet = processInputDataForJointInfo( avatar ); + + // Extract and parse wearables. + wearable_data.setWearableOutfit(mInputData["wearables"]); + + // Set appearance parameter to flag server-side baking. + avatar.setVisualParamWeight(APPEARANCE_PARAM_VERSION, 1.0f); + + avatar.setSex( (avatar.getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE ); + + avatar.updateVisualParams(); + + // Extract texture ids, texture hashes, and avatar scale. + LLSD texture_ids = LLSD::emptyMap(); + + //Process the params data for joint information + bool bodySizeSet = processInputDataForJointInfo( avatar ); + + //if we didn't compute a body size from a mesh attachment that included + //joint offsets we need to do it now + if (!bodySizeSet ) + { + avatar.computeBodySize(); + } + + for (U32 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) + { + EBakedTextureIndex bake_type = (EBakedTextureIndex) baked_index; + LLBakingTexLayerSet* layer_set = dynamic_cast(avatar.getAvatarLayerSet(bake_type)); + const std::string& slot_name = LLAvatarAppearance::getDictionary()->getTexture( + LLAvatarAppearance::getDictionary()->bakedToLocalTextureIndex(bake_type) )->mDefaultImageName; + texture_ids[slot_name] = layer_set->computeTextureIDs(); + } + + // Extract visual params + U32 count = 0; + LLSD params = LLSD::emptyMap(); + LLSD debug_params = LLSD::emptyMap(); + for (LLViewerVisualParam* param = (LLViewerVisualParam*)avatar.getFirstVisualParam(); + param; + param = (LLViewerVisualParam*)avatar.getNextVisualParam()) + { + if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE || + param->getGroup() == VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + { + const F32 param_value = param->getWeight(); + const U8 new_weight = F32_to_U8(param_value, param->getMinWeight(), param->getMaxWeight()); + LLSD body; + body["name"] = param->getName(); + body["value"] = param_value; + body["weight"] = new_weight; + debug_params[LLSD(param->getID()).asString()] = body; + params.append(new_weight); + count++; + } + } + + // Output + LLSD result; + result["success"] = true; + result["params"] = params; + result["debug_params"] = debug_params; + result["slot_textures"] = texture_ids; + result["avatar_scale"] = ll_sd_from_vector3(avatar.mBodySize + avatar.mAvatarOffset); + result["dump_joint_offsets"] = dump_joint_offsets_for_avatar(avatar); + output << LLSDOStreamer(result); +} + +bool LLProcessParams::processInputDataForJointInfo( LLBakingAvatar& avatar ) +{ + bool returnResult = false; + + if ( !mInputData.has("skindata") || mInputData["skindata"].isUndefined() ) + { + LL_DEBUGS() << "Skipping missing skindata" << LL_ENDL; + return returnResult; + } + + const LLSD& skindata = mInputData["skindata"]; + + //float pelvisOffset = 0.0f; + std::vector jointNames; + std::vector jointOffsets; + + LLSD::map_const_iterator skinIter = skindata.beginMap(); + LLSD::map_const_iterator skinIterEnd = skindata.endMap(); + + for ( ; skinIter!=skinIterEnd; ++skinIter ) + { + const LLSD& skin = skinIter->second; + const char *uuid_str = skinIter->first.c_str(); + const LLUUID mesh_id(uuid_str); + + if ( !skin.has("joint_names") || !skin.has("joint_offset") ) + { + throw LLAppException(RV_INVALID_SKIN_BLOCK); + } + + // Build list of joints + { + LLSD::array_const_iterator iter(skin["joint_names"].beginArray()); + LLSD::array_const_iterator iter_end(skin["joint_names"].endArray()); + for ( ; iter != iter_end; ++iter ) + { + jointNames.push_back( iter->asString() ); + } + } + // Extract joint offsets + { + LLSD::array_const_iterator iter(skin["joint_offset"].beginArray()); + LLSD::array_const_iterator iter_end(skin["joint_offset"].endArray()); + for ( ; iter != iter_end; ++iter ) + { + jointOffsets.push_back( ll_vector3_from_sd(*iter) ); + } + } + + // get at the *optional* pelvis offset + //if ( skin.has("pelvis_offset") ) + //{ + // pelvisOffset = skin["pelvis_offset"].asReal(); + //} + // Now apply the extracted joint data to the avatar + U32 jointCount = narrow(jointNames.size()); + + if ( jointOffsets.size() < jointCount ) + { + throw LLAppException(RV_INVALID_SKIN_BLOCK); + } + + bool fullRig = ( jointCount>= FULL_RIG_JOINT_COUNT ) ? true : false; + //bool pelvisGotSet = false; + + returnResult = fullRig; + + if ( fullRig ) + { + for ( U32 i=0; istoreCurrentXform( jointOffsets[i] ); + + bool active_override_changed = false; + pJoint->addAttachmentPosOverride(jointOffsets[i], mesh_id, "", active_override_changed); + } + } + + avatar.computeBodySize(); + avatar.mRoot->touch(); + avatar.mRoot->updateWorldMatrixChildren(); + + } + + jointNames.clear(); + jointOffsets.clear(); + } + return returnResult; +} diff --git a/indra/llappearanceutility/llprocessparams.h b/indra/llappearanceutility/llprocessparams.h new file mode 100644 index 00000000000..6df893fe219 --- /dev/null +++ b/indra/llappearanceutility/llprocessparams.h @@ -0,0 +1,49 @@ +/** + * @file llprocessparams.h + * @brief Declaration of LLProcessParams class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPROCESSPARAMS_H +#define LL_LLPROCESSPARAMS_H + +#include "llbakingprocess.h" + +class LLBakingAvatar; +class LLProcessParams : public LLBakingProcess +{ +public: + LLProcessParams(LLAppAppearanceUtility* app) : + LLBakingProcess(app) {} + + void process(std::ostream& output) override; +private: + + bool processInputDataForJointInfo( LLBakingAvatar& avatar ); +}; + + + + +#endif /* LL_LLPROCESSPARAMS_H */ + diff --git a/indra/llappearanceutility/llprocessskin.cpp b/indra/llappearanceutility/llprocessskin.cpp new file mode 100644 index 00000000000..a3d4d3c6f30 --- /dev/null +++ b/indra/llappearanceutility/llprocessskin.cpp @@ -0,0 +1,118 @@ +/** + * @file llprocessskin.cpp + * @brief Implementation of LLProcesSkin class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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$ + */ + +// linden includes +#include "linden_common.h" + +#include "llsd.h" +#include "llsdserialize.h" +#include "llsdutil.h" +#include "llsdutil_math.h" +#include "llstl.h" +#include "llmath.h" +#include "m4math.h" +#include "v4math.h" + +// project includes +#include "llappappearanceutility.h" +#include "llprocessskin.h" + +void LLProcessSkin::process(std::ostream& output) +{ + const LLSD& dataBlock = mInputData; + LLSD skinData = LLSD::emptyMap(); + + LLSD::map_const_iterator skinIter = dataBlock.beginMap(); + LLSD::map_const_iterator skinIterEnd = dataBlock.endMap(); + + for ( ; skinIter!=skinIterEnd; ++skinIter ) + { + const LLSD& skin = skinIter->second; + if ( !skin.has("joint_names") || !skin.has("alt_inverse_bind_matrix") ) + { + throw LLAppException(RV_INVALID_SKIN_BLOCK); + } + + LLSD entry = LLSD::emptyMap(); + + //get all joint names from the skin + { + entry["joint_names"] = LLSD::emptyArray(); + LLSD& joint_names = entry["joint_names"]; + LLSD::array_const_iterator iter(skin["joint_names"].beginArray()); + LLSD::array_const_iterator iter_end(skin["joint_names"].endArray()); + for ( ; iter != iter_end; ++iter ) + { + LL_DEBUGS() << "joint: " << iter->asString() << LL_ENDL; + joint_names.append(*iter); + } + } + //get at the translational component for the joint offsets + { + entry["joint_offset"] = LLSD::emptyArray(); + LLSD& joint_offsets = entry["joint_offset"]; + LLSD::array_const_iterator iter(skin["alt_inverse_bind_matrix"].beginArray()); + LLSD::array_const_iterator iter_end(skin["alt_inverse_bind_matrix"].endArray()); + //just get at the translational component + for ( ; iter != iter_end; ++iter ) + { + LLMatrix4 mat; + for (U32 j = 0; j < 4; j++) + { + for (U32 k = 0; k < 4; k++) + { + mat.mMatrix[j][k] = static_cast((*iter)[j*4+k].asReal()); + } + } + joint_offsets.append( ll_sd_from_vector3( mat.getTranslation() )); + LL_DEBUGS() << "offset: [" << mat.getTranslation()[0] << " " + << mat.getTranslation()[1] << " " + << mat.getTranslation()[2] << " ]" << LL_ENDL; + } + } + + //get at the *optional* pelvis offset + if (skin.has("pelvis_offset")) + { + entry["pelvis_offset"] = skin["pelvis_offset"]; + } + else + { + entry["pelvis_offset"] = LLSD::Real(0.f); + } + + //add block to outgoing result llsd + skinData[skinIter->first] = entry; + } + + //dump the result llsd into the outgoing output + LLSD result; + result["success"] = true; + result["skindata"] = skinData; + LL_DEBUGS() << "---------------------------\n" << result << LL_ENDL; + output << LLSDOStreamer(result); +} + diff --git a/indra/llappearanceutility/llprocessskin.h b/indra/llappearanceutility/llprocessskin.h new file mode 100644 index 00000000000..a3cc8c70876 --- /dev/null +++ b/indra/llappearanceutility/llprocessskin.h @@ -0,0 +1,43 @@ +/** + * @file llprocessskin.h + * @brief Declaration of LLProcessSkin class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPROCESSSKIN_H +#define LL_LLPROCESSSKIN_H + +#include "llbakingprocess.h" +class LLProcessSkin : public LLBakingProcess +{ +public: + LLProcessSkin(LLAppAppearanceUtility* app) : + LLBakingProcess(app) {} + void process(std::ostream& output) override; + +private: + +}; + +#endif /* LL_LLPROCESSSKIN_H */ + diff --git a/indra/llappearanceutility/llprocesstexture.cpp b/indra/llappearanceutility/llprocesstexture.cpp new file mode 100644 index 00000000000..91ceedc8f6e --- /dev/null +++ b/indra/llappearanceutility/llprocesstexture.cpp @@ -0,0 +1,285 @@ +/** + * @file llprocesstexture.cpp + * @brief Implementation of LLProcessTexture class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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$ + */ + +// linden includes +#include "linden_common.h" + +#include "llfasttimer.h" +#include "llgl.h" +#include "llimagej2c.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "llsdutil.h" + +// appearance includes +#include "llwearabletype.h" +#include "llavatarappearancedefines.h" + +// project includes +#include "llappappearanceutility.h" +#include "llbakingavatar.h" +#include "llbakingtexlayer.h" +#include "llbakingtexture.h" +#include "llbakingwearable.h" +#include "llbakingwearablesdata.h" +#include "llbakingwindow.h" +#include "llprocesstexture.h" + +static const S32 MAX_SIZE_LLSD_HEADER = 1024 * 1024; +static const bool USE_MIP_MAPS = true; + +static const S32 EYES_SLOT_DIMENSIONS=512; + +using namespace LLAvatarAppearanceDefines; + +LLProcessTexture::LLProcessTexture(LLAppAppearanceUtility* app) + : LLBakingProcess(app), + mWindow(nullptr), + mInputRaw(nullptr), + mBakeSize(512) +{ +} + +void LLProcessTexture::cleanup() +{ + delete mWindow; +} + +static LLFastTimer::DeclareTimer FTM_CREATE_TEXTURE_FROM_STREAM("Create texture from stream."); +static LLPointer create_texture_from_stream(std::istream& input, + S32 texture_size, + const LLUUID& id) +{ + LL_RECORD_BLOCK_TIME(FTM_CREATE_TEXTURE_FROM_STREAM); + // Read compressed j2c texture data from the input stream. + U8* buffer = (U8*) ll_aligned_malloc_16(texture_size); + input.read((char*) buffer, texture_size); + + if (input.gcount() < texture_size) + { + ll_aligned_free_16(buffer); + throw LLAppException(RV_UNABLE_TO_DECODE, " Early EOF in input stream."); + } + if (input.gcount() > texture_size) + { + ll_aligned_free_16(buffer); + throw LLAppException(RV_UNABLE_TO_DECODE, " Read too much data from input stream: Programming Error."); + } + + const S32 DISCARD_FULL_TEXTURE_RESOLUTION = 0; + LLPointer j2c = new LLImageJ2C(); + j2c->setDiscardLevel(DISCARD_FULL_TEXTURE_RESOLUTION); + // Transfer the j2c buffer to an LLImageJ2C object. + // This gives memory ownership of buffer to LLImageJ2C + if (!j2c->validate(buffer, texture_size)) + { + throw LLAppException(RV_UNABLE_TO_DECODE, " Unable to validate J2C: " + LLImage::getLastThreadError()); + } + if (!(j2c->getWidth() * j2c->getHeight() * j2c->getComponents() > 0)) + { + throw LLAppException(RV_UNABLE_TO_DECODE, " Invalid dimensions."); + } + + // Decompress the J2C image into a raw image. + LLPointer image_raw = new LLImageRaw(j2c->getWidth(), + j2c->getHeight(), + j2c->getComponents()); + const F32 MAX_DECODE_TIME = 60.f; + j2c->setDiscardLevel(0); + if (!j2c->decode(image_raw, MAX_DECODE_TIME)) + { + throw LLAppException(RV_UNABLE_TO_DECODE, " Decoding timeout."); + } + // *TODO: Check for decode failure? + LL_DEBUGS() << "ID: " << id << ", Raw Width: " << image_raw->getWidth() << ", Raw Height: " << image_raw->getHeight() + << ", Raw Components: " << (S32) image_raw->getComponents() + << ", J2C Width: " << j2c->getWidth() << ", J2C Height: " << j2c->getHeight() + << ", J2C Components: " << (S32) j2c->getComponents() << LL_ENDL; + + return image_raw; +} + +void LLProcessTexture::parseInput(std::istream& input) +{ + mInputRaw = &input; + LL_DEBUGS() << "Reading..." << LL_ENDL; + // Parse LLSD header. + mInputData = LLSDSerialize::fromBinary( *mInputRaw, MAX_SIZE_LLSD_HEADER ); + if (mInputData.isUndefined()) throw LLAppException(RV_UNABLE_TO_PARSE); + if (!mInputData.has("slot_id")) throw LLAppException(RV_UNABLE_TO_PARSE, " Missing slot id"); + if (!mInputData.has("textures")) throw LLAppException(RV_UNABLE_TO_PARSE, " Missing texture header"); + if (!mInputData.has("wearables")) throw LLAppException(RV_UNABLE_TO_PARSE, " Missing wearables"); + + // Verify the slot_id is valid. + if (BAKED_NUM_INDICES == LLAvatarAppearance::getDictionary()->findBakedByImageName(mInputData["slot_id"].asString())) + { + throw LLAppException(RV_UNABLE_TO_PARSE, " Invalid slot id"); + } +} + +void LLProcessTexture::init() +{ + if (mApp->isDebugMode()) gDebugGL = true; + + S32 maxTextureDecodedWidth = 0; + S32 maxTextureDecodedHeight = 0; + + // Extract texture data. + LLSD::array_const_iterator iter = mInputData["textures"].beginArray(); + LLSD::array_const_iterator end = mInputData["textures"].endArray(); + std::map< LLUUID, LLPointer > imageRawMap; + + for (; iter != end; ++iter) + { + LLUUID texture_id = (*iter)[0].asUUID(); + S32 texture_size = (*iter)[1]; + imageRawMap[texture_id] = create_texture_from_stream(*mInputRaw, texture_size, texture_id); + maxTextureDecodedWidth = imageRawMap[texture_id]->getWidth() > maxTextureDecodedWidth ? imageRawMap[texture_id]->getWidth() : maxTextureDecodedWidth; + maxTextureDecodedHeight = imageRawMap[texture_id]->getHeight() > maxTextureDecodedHeight ? imageRawMap[texture_id]->getHeight() : maxTextureDecodedHeight; + } + + if ("eyes" == mInputData["slot_id"].asString()) + { + mBakeSize = 512; + } + else + { + // optimization: maybe we could use maxTextureDecodedWidth and + // maxTextureDecodedHeight for new LLBakingWindow below? + if ((maxTextureDecodedWidth > 1024) || (maxTextureDecodedHeight > 1024)) + { + mBakeSize = 2048; + } + else if ((maxTextureDecodedWidth > 512) || (maxTextureDecodedHeight > 512)) + { + mBakeSize = 1024; + } + else + { + mBakeSize = 512; + } + } + + mWindow = new LLBakingWindow(mBakeSize, mBakeSize); + + for (iter = mInputData["textures"].beginArray(); iter != mInputData["textures"].endArray(); ++iter) + { + LLUUID texture_id = (*iter)[0].asUUID(); + + LLPointer texture = new LLBakingTexture(texture_id, imageRawMap[texture_id]); + texture->forceActive(); + texture->setGLTextureCreated(true); + + mTextureData[texture_id] = texture; + } + +} + +LLPointer LLProcessTexture::getLocalTexture(bool usemipmaps, bool generate_gl_tex) +{ + LLPointer tex = new LLBakingTexture(usemipmaps); + if(generate_gl_tex) + { + tex->generateGLTexture() ; + tex->setCategory(LLGLTexture::LOCAL) ; + } + return tex ; +} + +LLPointer LLProcessTexture::getLocalTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps, bool generate_gl_tex) +{ + LLPointer tex = new LLBakingTexture(width, height, components, usemipmaps) ; + if(generate_gl_tex) + { + tex->generateGLTexture() ; + tex->setCategory(LLGLTexture::LOCAL) ; + } + return tex ; +} + +LLGLTexture* LLProcessTexture::getFetchedTexture(const LLUUID &image_id) +{ + texture_map_t::iterator texture_iter = mTextureData.find(image_id); + if (mTextureData.end() == texture_iter) + { + LL_DEBUGS() << "Ignoring unused texture id: " << image_id << LL_ENDL; + return nullptr; + } + + return texture_iter->second; +} + +void LLProcessTexture::process(std::ostream& output) +{ + LL_DEBUGS() << "Building avatar..." << LL_ENDL; + // Set ourself as the texture bridge. + gTextureManagerBridgep = this; + + // Construct the avatar. + LLBakingWearablesData wearable_data; + LLBakingAvatar avatar(&wearable_data, mBakeSize); + avatar.initInstance(); + wearable_data.setAvatarAppearance(&avatar); + + // Extract and parse wearables. + wearable_data.setWearableOutfit(mInputData["wearables"]); + + avatar.setSex( (avatar.getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE ); + + avatar.updateVisualParams(); + + // Prepare gl for avatar baking + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + LLGLEnable color_mat(GL_COLOR_MATERIAL); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + EBakedTextureIndex bake_type = LLAvatarAppearance::getDictionary()->findBakedByImageName(mInputData["slot_id"].asString()); + LLTexLayerSet* layer_set = avatar.getAvatarLayerSet(bake_type); + LLBakingTexLayerSetBuffer* composite = dynamic_cast (layer_set->getComposite()); + if (!composite) + { + throw LLAppException(RV_UNABLE_TO_BAKE, " Could not build composite."); + } + + LL_DEBUGS() << "Rendering..." << LL_ENDL; + if (!composite->render()) + { + throw LLAppException(RV_UNABLE_TO_BAKE, " Failed to render composite."); + } + + mWindow->swapBuffers(); + + LL_DEBUGS() << "Compressing..." << LL_ENDL; + LLImageJ2C* j2c = composite->getCompressedImage(); + if (!j2c) + { + throw LLAppException(RV_UNABLE_TO_BAKE, " Could not build image."); + } + + LL_DEBUGS() << "Writing..." << LL_ENDL; + output.write((char*)j2c->getData(), j2c->getDataSize()); + LL_DEBUGS() << "Done." << LL_ENDL; +} diff --git a/indra/llappearanceutility/llprocesstexture.h b/indra/llappearanceutility/llprocesstexture.h new file mode 100644 index 00000000000..8bf2c7396f2 --- /dev/null +++ b/indra/llappearanceutility/llprocesstexture.h @@ -0,0 +1,63 @@ +/** + * @file llprocesstexture.h + * @brief Declaration of LLProcessTexture class. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPROCESSTEXTURE_H +#define LL_LLPROCESSTEXTURE_H + +#include "llbakingprocess.h" +#include "llbakingtexture.h" +#include "llpointer.h" +#include "lltexturemanagerbridge.h" +#include "llbakingwindow.h" + +class LLBakingWindow; + +class LLProcessTexture : public LLBakingProcess, public LLTextureManagerBridge +{ +public: + LLProcessTexture(LLAppAppearanceUtility* app); + + /////// LLBakingProcess interface. ///////// + void parseInput(std::istream& input) override; + void process(std::ostream& output) override; + void init() override; + void cleanup() override; + + /////// LLTextureManagerBridge interface. //////// + LLPointer getLocalTexture(bool usemipmaps = true, bool generate_gl_tex = true) override; + LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps, bool generate_gl_tex = true) override; + LLGLTexture* getFetchedTexture(const LLUUID &image_id) override; + +private: + typedef std::map< LLUUID, LLPointer > texture_map_t; + texture_map_t mTextureData; + LLBakingWindow* mWindow; + std::istream* mInputRaw; + S32 mBakeSize; +}; + +#endif /* LL_LLPROCESSTEXTURE_H */ + diff --git a/indra/llappearanceutility/tests/joint-offsets.xml b/indra/llappearanceutility/tests/joint-offsets.xml new file mode 100644 index 00000000000..4dca3c34298 --- /dev/null +++ b/indra/llappearanceutility/tests/joint-offsets.xml @@ -0,0 +1 @@ +92a7dd5c-bc30-9952-3b3b-e6cc10336cbebind_shape_matrix0.048803295940160750.00.00.00.00.0488033369183540340.00.00.00.00.049029946327209470.00.05886554718017578-0.03438653051853181.75724506378173831.0joint_namesmEyeLeftmHeadmNeckmChestmTorsomPelvismEyeRightalt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.090427502989768980.037174601107835770.080562800168991091.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.09042750298976898-0.037174601107835770.080562800168991091.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.06363839656114578-0.03717460110783577-1.89970004558563231.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.063638396561145780.03717460110783577-1.89970004558563231.0971cf873-afce-8b69-44d6-3f5879cb94c2bind_shape_matrix0.029928008094429970.00.00.00.00.046580597758293150.00.00.00.00.0094699859619140620.00.137737005949020395.450006574392319e-051.68836498260498051.0joint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenteralt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0359875001013278960.0-0.0253947004675865171.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.107000999152660370.0-0.026074899360537531.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03629549965262413-0.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.036295499652624130.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.020269699394702910.00.0053312801755964761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083006501197814940.0-0.0203639995306730271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083787396550178530.0-0.0266884993761777881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03427229821681976-0.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.034272298216819760.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0181128997355699540.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.018112899735569954-0.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0082314396277070050.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.008231439627707005-0.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.073194302618503570.00.087503999471664431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.104399003088474270.00.0171787999570369721.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.150499001145362850.00.0038539199158549311.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0291581992059946060.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.029158199205994606-0.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.00.0167011991143226620.00.0097117396071553231.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0341983996331691740.0-1.84081995487213131.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.105210997164249420.0-1.84016001224517821.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.141506999731063840.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14150699973106384-0.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.096935302019119260.0-1.82579004764556881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117205001413822170.0-1.82045996189117431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117986001074314120.0-1.81412994861602781.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.151476994156837460.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.15147699415683746-0.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.016323799267411232-0.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0163237992674112320.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.010020599700510502-0.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0100205997005105020.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.071405202150344850.0-1.9511599540710451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.102609001100063320.0-1.88242995738983151.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14870999753475190.0-1.86940002441406251.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.027369100600481033-0.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0273691006004810330.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.0-0.121913000941276550.0-1.78188002109527591.07e7a6834-8b41-4029-8f87-ce57b7d05beebind_shape_matrix0.27415099740028380.00.00.00.00.152832403779029850.00.00.00.00.23362004756927490.00.033084496855735780.01.74006009101867681.0joint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenteralt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0359875001013278960.0-0.0253947004675865171.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.107000999152660370.0-0.026074899360537531.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03629549965262413-0.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.036295499652624130.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.020269699394702910.00.0053312801755964761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083006501197814940.0-0.0203639995306730271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083787396550178530.0-0.0266884993761777881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03427229821681976-0.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.034272298216819760.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0181128997355699540.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.018112899735569954-0.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0082314396277070050.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.008231439627707005-0.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.073194302618503570.00.087503999471664431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.104399003088474270.00.0171787999570369721.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.150499001145362850.00.0038539199158549311.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0291581992059946060.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.029158199205994606-0.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.00.0167011991143226620.00.0097117396071553231.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0341983996331691740.0-1.84081995487213131.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.105210997164249420.0-1.84016001224517821.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.141506999731063840.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14150699973106384-0.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.096935302019119260.0-1.82579004764556881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117205001413822170.0-1.82045996189117431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117986001074314120.0-1.81412994861602781.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.151476994156837460.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.15147699415683746-0.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.016323799267411232-0.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0163237992674112320.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.010020599700510502-0.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0100205997005105020.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.071405202150344850.0-1.9511599540710451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.102609001100063320.0-1.88242995738983151.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14870999753475190.0-1.86940002441406251.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.027369100600481033-0.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0273691006004810330.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.0-0.121913000941276550.0-1.78188002109527591.0547d8392-9f19-35fb-3508-121eea388f0abind_shape_matrix0.12420170754194260.00.00.00.00.040834598243236540.00.00.00.00.0144999027252197270.00.077383153140544890.01.68994998931884771.0joint_namesmFaceJawmFaceRootmHeadmNeckmChestmTorsomPelvismFaceTongueBasemFaceTeethLowermFaceTongueTipalt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0359875001013278960.0-0.0253947004675865171.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0298503991216421130.00.0078316899016499521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083006501197814940.0-0.0203639995306730271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0389162003993988040.0-0.0027754299808293581.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0341983996331691740.0-1.84081995487213131.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.087354503571987150.0-1.82828998565673831.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117205001413822170.0-1.82045996189117431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.126270994544029240.0-1.8255100250244141.0ed796a27-cff0-454a-ecec-fd10794ca2c9bind_shape_matrix0.0071529899723827840.00.00.00.00.0193126909434795380.00.00.00.00.0236200094223022460.00.163101494312286380.00020919507369399071.71106004714965821.0joint_namesmFaceNoseBasemFaceRootmHeadmNeckmChestmTorsomPelvismFaceLipUpperCentermFaceTeethUpperalt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.150499001145362850.00.0038539199158549311.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.00.0167011991143226620.00.0097117396071553231.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.107000999152660370.0-0.026074899360537531.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14870999753475190.0-1.86940002441406251.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.0-0.121913000941276550.0-1.78188002109527591.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.105210997164249420.0-1.84016001224517821.0fa0aabfe-4b1c-fa9b-4942-74e7e7f50fe2bind_shape_matrix0.022715998813509940.00.00.00.00.022715998813509940.00.00.00.00.0227099657058715820.00.00.01.06701493263244631.0joint_namesmPelvismHandMiddle1LeftmHandMiddle2LeftmHandMiddle3LeftmHandIndex1LeftmHandIndex2LeftmHandIndex3LeftmHandRing1LeftmHandRing2LeftmHandRing3LeftmHandPinky1LeftmHandPinky2LeftmHandPinky3LeftmHandThumb1LeftmHandThumb2LeftmHandThumb3LeftmHandMiddle1RightmHandMiddle2RightmHandMiddle3RightmHandIndex1RightmHandIndex2RightmHandIndex3RightmHandRing1RightmHandRing2RightmHandRing3RightmHandPinky1RightmHandPinky2RightmHandPinky3RightmHandThumb1RightmHandThumb2RightmHandThumb3Rightalt_inverse_bind_matrix1.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.00.99873197078704830.04983130097389221-0.0070897499099373820.0-0.0301342997699975970.7048000097274780.7087659835815430.00.040315598249435425-0.70765399932861330.7054079771041870.00.0151886995881795880.098942197859287260.0104294996708631521.00.99894601106643680.045610301196575165-0.005135800223797560.0-0.0289570000022649770.71308398246765140.70047998428344730.00.03561139851808548-0.69959300756454470.71365398168563840.0-0.00105056003667414190.04202070087194443-0.0063029900193214421.00.99634701013565060.08039940148591995-0.028780499473214150.0-0.0383009985089302060.72195601463317870.69087797403335570.00.07632440328598022-0.68725198507308960.72239899635314940.0-0.00050425098743289710.024710899218916893-0.0040346500463783741.00.9319689869880676-0.248298004269599910.264160990715026860.00.023382499814033510.7682970166206360.63966602087020870.0-0.3617820143699646-0.5899729728698730.72183501720428470.00.03427390009164810.094680696725845340.0096299396827816961.00.9427329897880554-0.223545998334884640.24755300581455230.00.017677599564194680.7746199965476990.63217902183532710.0-0.333079993724823-0.59160000085830690.73421198129653930.00.0171910002827644350.03640490025281906-0.0060679200105369091.00.9429500102996826-0.21653699874877930.25289699435234070.00.002694060094654560.76453900337219240.64457201957702640.0-0.3329229950904846-0.60711801052093510.72150599956512450.00.0102137001231312750.023345300927758217-0.0043774899095296861.00.9654129743576050.157709002494812-0.207616999745368960.00.0155645003542304040.76002901792526250.64970201253890990.00.2602590024471283-0.63046300411224370.73128801584243770.0-0.00364764011465013030.096580803394317630.0044052097946405411.00.97247397899627690.11432900279760361-0.203038007020950320.00.044799100607633590.76336401700973510.64441400766372680.00.2286670058965683-0.63577097654342650.73722898960113530.0-0.0123153002932667730.035998500883579254-0.0075785201042890551.00.96376097202301030.15707699954509735-0.21561999619007110.00.0189111009240150450.76600497961044310.64255702495574950.00.2660970091819763-0.62334901094436650.73527497053146360.0-0.0065627098083496090.02019299939274788-0.0045438897795975211.00.82219499349594120.3776470124721527-0.42588400840759280.0-0.118125997483730320.84512501955032350.5213530063629150.00.5568130016326904-0.37834599614143370.7394679784774780.0-0.0232133995741605760.08812329918146133-0.0041738501749932771.00.86176002025604250.33954399824142456-0.37693598866462710.0-0.106248997151851650.84731501340866090.52035301923751830.00.49606600403785706-0.40837100148200990.76625800132751460.0-0.0222677998244762420.02319590002298355-0.0055669201537966731.00.87477701902389530.3211840093135834-0.36277499794960020.0-0.108980998396873470.85996502637863160.49858099222183230.00.47211000323295593-0.39661198854446410.78728097677230830.0-0.012436700053513050.014924099668860435-0.0033164799679070711.00.9163669943809509-0.072017200291156770.39380899071693420.0-0.11881099641323090.89044702053070070.4393039941787720.0-0.38230299949645996-0.44935199618339540.8074200153350830.00.032215598970651630.02088090032339096-0.008553059771656991.00.9283679723739624-0.0201622005552053450.37111499905586240.0-0.166196003556251530.87061101198196410.46305000782012940.0-0.33243298530578613-0.49155899882316590.80489701032638550.00.0294509995728731160.03365840017795563-0.00105202000122517351.00.9289919734001160.079554900527000430.36144900321960450.0-0.26165801286697390.83187001943588260.48941498994827270.0-0.2617430090904236-0.54923802614212040.79361701011657710.00.0209248997271060940.028203699737787247-0.0009096220019273461.00.9987319707870483-0.04983120039105415-0.0070897699333727360.00.0301342997699975970.704800009727478-0.7087659835815430.00.0403155013918876650.70765399932861330.7054079771041870.00.015188699588179588-0.098942197859287260.0104294996708631521.00.9989460110664368-0.045610301196575165-0.005135800223797560.00.0289570000022649770.7130839824676514-0.70047998428344730.00.035611398518085480.69959300756454470.71365398168563840.0-0.0010505500249564648-0.042020801454782486-0.0063028801232576371.00.9963470101356506-0.08039940148591995-0.028780499473214150.00.0383009985089302060.7219560146331787-0.69087797403335570.00.076324403285980220.68725198507308960.72239899635314940.0-0.0005042660050094128-0.024710899218916893-0.00403465982526540761.00.93196898698806760.248298004269599910.264160990715026860.0-0.0233826003968715670.768297016620636-0.63966697454452510.0-0.36178201436996460.5899729728698730.72183501720428470.00.0342739000916481-0.094680696725845340.0096299396827816961.00.94273298978805540.223545998334884640.24755300581455230.0-0.0176777001470327380.774619996547699-0.63217902183532710.0-0.3330799937248230.59160000085830690.73421198129653930.00.017191000282764435-0.03640500083565712-0.0060678198933601381.00.94295001029968260.21653699874877930.25289699435234070.0-0.0026940701063722370.7645390033721924-0.64457201957702640.0-0.33292299509048460.60711801052093510.72150599956512450.00.010213700123131275-0.023345300927758217-0.0043774899095296861.00.965412974357605-0.157709002494812-0.207616999745368960.0-0.0155645003542304040.7600290179252625-0.64970201253890990.00.26025900244712830.63046300411224370.73128801584243770.0-0.0036476401146501303-0.096580803394317630.0044052097946405411.00.9724739789962769-0.11432900279760361-0.203038007020950320.0-0.044799100607633590.7633640170097351-0.64441400766372680.00.22866700589656830.63577097654342650.73722898960113530.0-0.012315300293266773-0.035998400300741196-0.0075783901847898961.00.9637609720230103-0.15707699954509735-0.21561999619007110.0-0.0189111009240150450.7660049796104431-0.64255702495574950.00.26609700918197630.62334901094436650.73527497053146360.0-0.006562769878655672-0.02019290067255497-0.0045436499640345571.00.8221949934959412-0.3776470124721527-0.42588400840759280.00.118125997483730320.8451250195503235-0.5213530063629150.00.55681300163269040.37834599614143370.7394679784774780.0-0.023213399574160576-0.08812329918146133-0.0041738501749932771.00.8617600202560425-0.33954399824142456-0.37693598866462710.00.106248997151851650.8473150134086609-0.52035301923751830.00.496066004037857060.40837100148200990.76625800132751460.0-0.022267799824476242-0.023195700719952583-0.0055669001303613191.00.8747770190238953-0.3211840093135834-0.36277499794960020.00.108980998396873470.8599650263786316-0.49858099222183230.00.472110003232955930.39661198854446410.78728097677230830.0-0.012436600401997566-0.014924000017344952-0.00331673002801835541.00.91636699438095090.072017401456832890.39380899071693420.00.11881099641323090.8904470205307007-0.4393039941787720.0-0.382302999496459960.44935199618339540.8074200153350830.00.03221559897065163-0.02088090032339096-0.008553059771656991.00.92836797237396240.0201622005552053450.37111499905586240.00.166196003556251530.8706110119819641-0.46305000782012940.0-0.332432985305786130.49155899882316590.80489701032638550.00.029450900852680206-0.03365840017795563-0.00105209997855126861.00.928991973400116-0.079554900527000430.36144900321960450.00.26165801286697390.8318700194358826-0.48941498994827270.0-0.26174300909042360.54923802614212040.79361701011657710.00.020925000309944153-0.028203800320625305-0.00090978998923674231.0pelvis_offset0.0inverse_bind_matrix1.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.0670200586318971.00.99873197078704830.04983130097389221-0.0070897499099373820.0-0.0301342997699975970.7048000097274780.7087659835815430.00.040315598249435425-0.70765399932861330.7054079771041870.0-0.0084887603297829630.41053301095962524-1.20159995555877691.00.99894601106643680.045610301196575165-0.005135800223797560.0-0.0289570000022649770.71308398246765140.70047998428344730.00.03561139851808548-0.69959300756454470.71365398168563840.0-0.00293081998825073240.35466399788856506-1.19949996471405031.00.99634701013565060.08039940148591995-0.028780499473214150.0-0.0383009985089302060.72195601463317870.69087797403335570.00.07632440328598022-0.68725198507308960.72239899635314940.0-0.040985401719808580.3118860125541687-1.19960999488830571.00.9319689869880676-0.248298004269599910.264160990715026860.00.023382499814033510.7682970166206360.63966602087020870.0-0.3617820143699646-0.5899729728698730.72183501720428470.00.401042997837066650.2437240034341812-1.18042004108428961.00.9427329897880554-0.223545998334884640.24755300581455230.00.017677599564194680.7746199965476990.63217902183532710.0-0.333079993724823-0.59160000085830690.73421198129653930.00.355307996273040770.2053389996290207-1.1836500167846681.00.9429500102996826-0.21653699874877930.25289699435234070.00.002694060094654560.76453900337219240.64457201957702640.0-0.3329229950904846-0.60711801052093510.72150599956512450.00.353888005018234250.2048649936914444-1.17289996147155761.00.9654129743576050.157709002494812-0.207616999745368960.00.0155645003542304040.76002901792526250.64970201253890990.00.2602590024471283-0.63046300411224370.73128801584243770.0-0.26629498600959780.2996309995651245-1.20013999938964841.00.97247397899627690.11432900279760361-0.203038007020950320.00.044799100607633590.76336401700973510.64441400766372680.00.2286670058965683-0.63577097654342650.73722898960113530.0-0.23568700253963470.26565900444984436-1.19586002826690671.00.96376097202301030.15707699954509735-0.21561999619007110.00.0189111009240150450.76600497961044310.64255702495574950.00.2660970091819763-0.62334901094436650.73527497053146360.0-0.25492200255393980.23242099583148956-1.1886899471282961.00.82219499349594120.3776470124721527-0.42588400840759280.0-0.118125997483730320.84512501955032350.5213530063629150.00.5568130016326904-0.37834599614143370.7394679784774780.0-0.5196760296821594-0.007902019657194614-1.14863002300262451.00.86176002025604250.33954399824142456-0.37693598866462710.0-0.106248997151851650.84731501340866090.52035301923751830.00.49606600403785706-0.40837100148200990.76625800132751460.0-0.4340290129184723-0.0015098199946805835-1.1690100431442261.00.87477701902389530.3211840093135834-0.36277499794960020.0-0.108980998396873470.85996502637863160.49858099222183230.00.47211000323295593-0.39661198854446410.78728097677230830.0-0.3928540050983429-0.03789449855685234-1.17518997192382811.00.9163669943809509-0.072017200291156770.39380899071693420.0-0.11881099641323090.89044702053070070.4393039941787720.0-0.38230299949645996-0.44935199618339540.8074200153350830.00.513168990612030.09074380248785019-1.16830003261566161.00.9283679723739624-0.0201622005552053450.37111499905586240.0-0.166196003556251530.87061101198196410.46305000782012940.0-0.33243298530578613-0.49155899882316590.80489701032638550.00.450581997632980350.11499100178480148-1.17621004581451421.00.9289919734001160.079554900527000430.36144900321960450.0-0.26165801286697390.83187001943588260.48941498994827270.0-0.2617430090904236-0.54923802614212040.79361701011657710.00.4012039899826050.1690800040960312-1.17639994621276861.00.9987319707870483-0.04983120039105415-0.0070897699333727360.00.0301342997699975970.704800009727478-0.7087659835815430.00.0403155013918876650.70765399932861330.7054079771041870.0-0.008488760329782963-0.41053301095962524-1.20159995555877691.00.9989460110664368-0.045610301196575165-0.005135800223797560.00.0289570000022649770.7130839824676514-0.70047998428344730.00.035611398518085480.69959300756454470.71365398168563840.0-0.0029308199882507324-0.35466399788856506-1.19949996471405031.00.9963470101356506-0.08039940148591995-0.028780499473214150.00.0383009985089302060.7219560146331787-0.69087797403335570.00.076324403285980220.68725198507308960.72239899635314940.0-0.04098540171980858-0.3118860125541687-1.19960999488830571.00.93196898698806760.248298004269599910.264160990715026860.0-0.0233826003968715670.768297016620636-0.63966697454452510.0-0.36178201436996460.5899729728698730.72183501720428470.00.40104299783706665-0.2437240034341812-1.18042004108428961.00.94273298978805540.223545998334884640.24755300581455230.0-0.0176777001470327380.774619996547699-0.63217902183532710.0-0.3330799937248230.59160000085830690.73421198129653930.00.35530799627304077-0.2053389996290207-1.1836500167846681.00.94295001029968260.21653699874877930.25289699435234070.0-0.0026940701063722370.7645390033721924-0.64457201957702640.0-0.33292299509048460.60711801052093510.72150599956512450.00.35388800501823425-0.2048649936914444-1.17289996147155761.00.965412974357605-0.157709002494812-0.207616999745368960.0-0.0155645003542304040.7600290179252625-0.64970201253890990.00.26025900244712830.63046300411224370.73128801584243770.0-0.2662949860095978-0.2996309995651245-1.20013999938964841.00.9724739789962769-0.11432900279760361-0.203038007020950320.0-0.044799100607633590.7633640170097351-0.64441400766372680.00.22866700589656830.63577097654342650.73722898960113530.0-0.2356870025396347-0.26565900444984436-1.19586002826690671.00.9637609720230103-0.15707699954509735-0.21561999619007110.0-0.0189111009240150450.7660049796104431-0.64255702495574950.00.26609700918197630.62334901094436650.73527497053146360.0-0.2549220025539398-0.23242099583148956-1.1886899471282961.00.8221949934959412-0.3776470124721527-0.42588400840759280.00.118125997483730320.8451250195503235-0.5213530063629150.00.55681300163269040.37834599614143370.7394679784774780.0-0.51967602968215940.007902019657194614-1.14863002300262451.00.8617600202560425-0.33954399824142456-0.37693598866462710.00.106248997151851650.8473150134086609-0.52035301923751830.00.496066004037857060.40837100148200990.76625800132751460.0-0.43402901291847230.0015098199946805835-1.1690100431442261.00.8747770190238953-0.3211840093135834-0.36277499794960020.00.108980998396873470.8599650263786316-0.49858099222183230.00.472110003232955930.39661198854446410.78728097677230830.0-0.39285400509834290.03789449855685234-1.17518997192382811.00.91636699438095090.072017401456832890.39380899071693420.00.11881099641323090.8904470205307007-0.4393039941787720.0-0.382302999496459960.44935199618339540.8074200153350830.00.51316899061203-0.0907440036535263-1.16830003261566161.00.92836797237396240.0201622005552053450.37111499905586240.00.166196003556251530.8706110119819641-0.46305000782012940.0-0.332432985305786130.49155899882316590.80489701032638550.00.45058199763298035-0.11499100178480148-1.17621004581451421.00.928991973400116-0.079554900527000430.36144900321960450.00.26165801286697390.8318700194358826-0.48941498994827270.0-0.26174300909042360.54923802614212040.79361701011657710.00.401203989982605-0.1690800040960312-1.17639994621276861.015659a9a-f1c1-3e38-8343-2e23e9f65d20bind_shape_matrix0.129504993557930.00.00.00.00.097699806094169620.00.00.00.00.138080000877380370.00.021911798045039177-0.0570470988750457761.83544993400573731.0joint_namesmHeadmNeckmChestmTorsomPelvismFaceEar2RightmFaceEar1RightmFaceRootmFaceEar1LeftmFaceEar2Leftalt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.00.00.00.00.01.00.00.00.00.01.00.00.0142705999314785-0.0175573993474245070.056489199399948121.01.00.00.00.00.01.00.00.00.00.01.00.00.0041375597938895226-0.047394301742315290.089543297886848451.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.00.00.00.00.01.00.00.00.00.01.00.00.00413755979388952260.047394301742315290.089543297886848451.01.00.00.00.00.01.00.00.00.00.01.00.00.01427059993147850.0175573993474245070.056489199399948121.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.00.00.00.00.01.00.00.00.00.01.00.0-0.0164429005235433580.062392398715019226-1.86315000057220461.01.00.00.00.00.01.00.00.00.00.01.00.0-0.00217230990529060360.04483500123023987-1.80666005611419681.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.00.00.00.00.01.00.00.00.00.01.00.0-0.0021723099052906036-0.04483500123023987-1.80666005611419681.01.00.00.00.00.01.00.00.00.00.01.00.0-0.016442900523543358-0.062392398715019226-1.86315000057220461.01d5936bc-0501-7376-f70c-06dcfac920edbind_shape_matrix0.048803295940160750.00.00.00.00.0488033369183540340.00.00.00.00.049029946327209470.00.058865547180175780.03438653051853181.75724506378173831.0joint_namesmEyeLeftmHeadmNeckmChestmTorsomPelvismEyeRightalt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.090427502989768980.037174601107835770.080562800168991091.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.09042750298976898-0.037174601107835770.080562800168991091.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.06363839656114578-0.03717460110783577-1.89970004558563231.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.063638396561145780.03717460110783577-1.89970004558563231.09174c7f1-bd5f-68d2-2f4f-cc9b36312067bind_shape_matrix0.083263903856277470.00.00.00.00.125166594982147220.00.00.00.00.105179905891418460.00.113597050309181210.01.73993992805480961.0joint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenteralt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0359875001013278960.0-0.0253964997828006741.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.107000999152660370.0-0.0260765999555587771.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03629549965262413-0.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.036295499652624130.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.020269699394702910.00.0053312801755964761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083006501197814940.0-0.0203639995306730271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083787396550178530.0-0.0266884993761777881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03427229821681976-0.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.034272298216819760.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.038352798670530321.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.038352798670530321.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0181128997355699540.0167341008782386780.057003501802682881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.018112899735569954-0.0167341008782386780.057003501802682881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0082314396277070050.037603501230478290.056274298578500751.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.008231439627707005-0.037603501230478290.056274298578500751.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.073194302618503570.00.087502397596836091.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.104399003088474270.00.0171770993620157241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.150499001145362850.00.00385225005447864531.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.038352798670530321.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.038352798670530321.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0291581992059946060.05687420070171356-0.0045324601233005521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.029158199205994606-0.05687420070171356-0.0045324601233005521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.00.0167011991143226620.00.0097117396071553231.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0341983996331691740.0-1.84081995487213131.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.105210997164249420.0-1.8401499986648561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.141506999731063840.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14150699973106384-0.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.096935302019119260.0-1.82579004764556881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117205001413822170.0-1.8204499483108521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117986001074314120.0-1.81412994861602781.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.151476994156837460.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.15147699415683746-0.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.016323799267411232-0.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0163237992674112320.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.010020599700510502-0.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0100205997005105020.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.071405202150344850.0-1.95114994049072271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.102609001100063320.0-1.88242995738983151.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14870999753475190.0-1.86940002441406251.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.027369100600481033-0.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0273691006004810330.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.0-0.121913000941276550.0-1.78188002109527591.0d73dea3b-b8cb-59ff-c76b-cfdcc8119bb5bind_shape_matrix0.088992610573768620.00.00.00.00.063932202756404880.00.00.00.00.0207600593566894530.00.103547699749469760.01.6937500238418581.0joint_namesmFaceJawmFaceRootmHeadmNeckmChestmTorsomPelvisalt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0359875001013278960.0-0.0253947004675865171.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0341983996331691740.0-1.84081995487213131.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.0d0328b82-d9ca-6071-b248-17edfc7612cbbind_shape_matrix0.135498702526092530.00.00.00.00.14647419750690460.00.00.00.00.120779991149902340.00.103381648659706120.01.74884998798370361.0joint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenteralt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0359875001013278960.0-0.0253947004675865171.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.107000999152660370.0-0.026074899360537531.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03629549965262413-0.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.036295499652624130.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.020269699394702910.00.0053312801755964761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083006501197814940.0-0.0203639995306730271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083787396550178530.0-0.0266884993761777881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03427229821681976-0.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.034272298216819760.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0181128997355699540.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.018112899735569954-0.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0082314396277070050.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.008231439627707005-0.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.073194302618503570.00.087503999471664431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.104399003088474270.00.0171787999570369721.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.150499001145362850.00.0038539199158549311.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0291581992059946060.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.029158199205994606-0.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.00.0167011991143226620.00.0097117396071553231.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0341983996331691740.0-1.84081995487213131.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.105210997164249420.0-1.84016001224517821.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.141506999731063840.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14150699973106384-0.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.096935302019119260.0-1.82579004764556881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117205001413822170.0-1.82045996189117431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117986001074314120.0-1.81412994861602781.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.151476994156837460.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.15147699415683746-0.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.016323799267411232-0.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0163237992674112320.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.010020599700510502-0.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0100205997005105020.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.071405202150344850.0-1.9511599540710451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.102609001100063320.0-1.88242995738983151.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14870999753475190.0-1.86940002441406251.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.027369100600481033-0.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0273691006004810330.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.0-0.121913000941276550.0-1.78188002109527591.005bf604d-d1c0-352b-cb2f-c37caca6f542bind_shape_matrix0.0145499994978308680.00.00.00.00.0359961986541748050.00.00.00.00.0196599960327148440.00.13412399590015410.01.69300997257232671.0joint_namesmFaceJawmFaceRootmHeadmNeckmChestmTorsomPelvisalt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0359875001013278960.0-0.0253947004675865171.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0341983996331691740.0-1.84081995487213131.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.046ee8fb2-15f0-fa2e-d260-e7e6e8295445bind_shape_matrix0.144471108913421630.00.00.00.00.079346001148223880.00.00.00.00.03420996665954590.00.078120440244674680.01.697255015373231.0joint_namesmFaceJawmFaceRootmHeadmNeckmChestmTorsomPelvisalt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0359875001013278960.0-0.0253947004675865171.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0341983996331691740.0-1.84081995487213131.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.0d2205615-2ce0-4ff1-2bfd-bdc77a3825ccbind_shape_matrix0.065835200250148770.00.00.00.00.19282799959182740.00.00.00.00.105929970741271970.00.020774498581886290.01.71460509300231931.0joint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenteralt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0359875001013278960.0-0.0253947004675865171.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.107000999152660370.0-0.026074899360537531.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03629549965262413-0.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.036295499652624130.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.020269699394702910.00.0053312801755964761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083006501197814940.0-0.0203639995306730271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083787396550178530.0-0.0266884993761777881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03427229821681976-0.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.034272298216819760.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0181128997355699540.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.018112899735569954-0.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0082314396277070050.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.008231439627707005-0.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.073194302618503570.00.087503999471664431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.104399003088474270.00.0171787999570369721.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.150499001145362850.00.0038539199158549311.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0291581992059946060.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.029158199205994606-0.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.00.0167011991143226620.00.0097117396071553231.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0341983996331691740.0-1.84081995487213131.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.105210997164249420.0-1.84016001224517821.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.141506999731063840.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14150699973106384-0.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.096935302019119260.0-1.82579004764556881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117205001413822170.0-1.82045996189117431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117986001074314120.0-1.81412994861602781.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.151476994156837460.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.15147699415683746-0.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.016323799267411232-0.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0163237992674112320.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.010020599700510502-0.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0100205997005105020.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.071405202150344850.0-1.9511599540710451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.102609001100063320.0-1.88242995738983151.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14870999753475190.0-1.86940002441406251.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.027369100600481033-0.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0273691006004810330.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.0-0.121913000941276550.0-1.78188002109527591.08665c374-cb61-d418-d412-7f4ea828e119bind_shape_matrix0.66893059015274050.00.00.00.00.171288996934890750.00.00.00.00.19170999526977540.0-0.406830698251724240.01.12604498863220211.0joint_namesmTail1mPelvismTail2mTail3mTail4mTail6mTail5alt_inverse_bind_matrix1.00.00.00.00.01.00.00.00.00.01.00.0-0.165999993681907650.00.067000001668930051.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.00.00.00.00.01.00.00.00.00.01.00.0-0.147750005125999450.00.01.01.00.00.00.00.01.00.00.00.00.01.00.0-0.126000002026557920.00.01.01.00.00.00.00.01.00.00.00.00.01.00.0-0.106499999761581420.00.01.01.00.00.00.00.01.00.00.00.00.01.00.0-0.070500001311302190.00.01.01.00.00.00.00.01.00.00.00.00.01.00.0-0.083999998867511750.00.01.0pelvis_offset0.0inverse_bind_matrix1.00.00.00.00.01.00.00.00.00.01.00.00.165999993681907650.0-1.13401997089385991.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.0670200586318971.01.00.00.00.00.01.00.00.00.00.01.00.00.31374999880790710.0-1.13401997089385991.01.00.00.00.00.01.00.00.00.00.01.00.00.439749985933303830.0-1.13401997089385991.01.00.00.00.00.01.00.00.00.00.01.00.00.54624998569488530.0-1.13401997089385991.01.00.00.00.00.01.00.00.00.00.01.00.00.70074999332427980.0-1.13401997089385991.01.00.00.00.00.01.00.00.00.00.01.00.00.63024997711181640.0-1.13401997089385991.0e678576a-dc9f-5187-6ed5-5b4aafb65d7bbind_shape_matrix0.0103429928421974180.00.00.00.00.060677599161863330.00.00.00.00.0129300355911254880.00.111756503582000730.01.68668508529663091.0joint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenteralt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0359875001013278960.0-0.0253947004675865171.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.107000999152660370.0-0.026074899360537531.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03629549965262413-0.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.036295499652624130.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.020269699394702910.00.0053312801755964761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083006501197814940.0-0.0203639995306730271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083787396550178530.0-0.0266884993761777881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03427229821681976-0.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.034272298216819760.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0181128997355699540.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.018112899735569954-0.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0082314396277070050.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.008231439627707005-0.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.073194302618503570.00.087503999471664431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.104399003088474270.00.0171787999570369721.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.150499001145362850.00.0038539199158549311.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0291581992059946060.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.029158199205994606-0.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.00.0167011991143226620.00.0097117396071553231.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0341983996331691740.0-1.84081995487213131.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.105210997164249420.0-1.84016001224517821.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.141506999731063840.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14150699973106384-0.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.096935302019119260.0-1.82579004764556881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117205001413822170.0-1.82045996189117431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117986001074314120.0-1.81412994861602781.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.151476994156837460.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.15147699415683746-0.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.016323799267411232-0.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0163237992674112320.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.010020599700510502-0.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0100205997005105020.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.071405202150344850.0-1.9511599540710451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.102609001100063320.0-1.88242995738983151.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14870999753475190.0-1.86940002441406251.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.027369100600481033-0.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0273691006004810330.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.0-0.121913000941276550.0-1.78188002109527591.08d23b8c8-fadf-c1b3-0b04-a3ecea292576bind_shape_matrix0.129504993557930.00.00.00.00.097699806094169620.00.00.00.00.138080000877380370.00.0219117980450391770.0570470988750457761.83544993400573731.0joint_namesmHeadmNeckmChestmTorsomPelvismFaceEar2RightmFaceEar1RightmFaceRootmFaceEar1LeftmFaceEar2Leftalt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.00.00.00.00.01.00.00.00.00.01.00.00.0142705999314785-0.0175573993474245070.056489199399948121.01.00.00.00.00.01.00.00.00.00.01.00.00.0041375597938895226-0.047394301742315290.089543297886848451.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.00.00.00.00.01.00.00.00.00.01.00.00.00413755979388952260.047394301742315290.089543297886848451.01.00.00.00.00.01.00.00.00.00.01.00.00.01427059993147850.0175573993474245070.056489199399948121.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.00.00.00.00.01.00.00.00.00.01.00.0-0.0164429005235433580.062392398715019226-1.86315000057220461.01.00.00.00.00.01.00.00.00.00.01.00.0-0.00217230990529060360.04483500123023987-1.80666005611419681.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.00.00.00.00.01.00.00.00.00.01.00.0-0.0021723099052906036-0.04483500123023987-1.80666005611419681.01.00.00.00.00.01.00.00.00.00.01.00.0-0.016442900523543358-0.062392398715019226-1.86315000057220461.02a30e7ec-9840-f495-daa1-2b8d0d025a78bind_shape_matrix0.064477898180484770.00.00.00.00.069889500737190250.00.00.00.00.105170004069805150.00.0064538493752479550.078819252550601961.84524500370025631.0joint_namesmHeadmNeckmChestmTorsomPelvismFaceEar2RightmFaceEar1RightmFaceRootmFaceEar1LeftmFaceEar2Leftalt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.00.00.00.00.01.00.00.00.00.01.00.00.0142705999314785-0.0175573993474245070.056489199399948121.01.00.00.00.00.01.00.00.00.00.01.00.00.0041375597938895226-0.047394301742315290.089543297886848451.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.00.00.00.00.01.00.00.00.00.01.00.00.00413755979388952260.047394301742315290.089543297886848451.01.00.00.00.00.01.00.00.00.00.01.00.00.01427059993147850.0175573993474245070.056489199399948121.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.00.00.00.00.01.00.00.00.00.01.00.0-0.0164429005235433580.062392398715019226-1.86315000057220461.01.00.00.00.00.01.00.00.00.00.01.00.0-0.00217230990529060360.04483500123023987-1.80666005611419681.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.00.00.00.00.01.00.00.00.00.01.00.0-0.0021723099052906036-0.04483500123023987-1.80666005611419681.01.00.00.00.00.01.00.00.00.00.01.00.0-0.016442900523543358-0.062392398715019226-1.86315000057220461.03bd8d73d-be6f-8de2-39ae-1f680189bc27bind_shape_matrix0.064477898180484770.00.00.00.00.069889500737190250.00.00.00.00.105170004069805150.00.006453849375247955-0.078819252550601961.84524500370025631.0joint_namesmHeadmNeckmChestmTorsomPelvismFaceEar2RightmFaceEar1RightmFaceRootmFaceEar1LeftmFaceEar2Leftalt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.00.00.00.00.01.00.00.00.00.01.00.00.0142705999314785-0.0175573993474245070.056489199399948121.01.00.00.00.00.01.00.00.00.00.01.00.00.0041375597938895226-0.047394301742315290.089543297886848451.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.00.00.00.00.01.00.00.00.00.01.00.00.00413755979388952260.047394301742315290.089543297886848451.01.00.00.00.00.01.00.00.00.00.01.00.00.01427059993147850.0175573993474245070.056489199399948121.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.00.00.00.00.01.00.00.00.00.01.00.0-0.0164429005235433580.062392398715019226-1.86315000057220461.01.00.00.00.00.01.00.00.00.00.01.00.0-0.00217230990529060360.04483500123023987-1.80666005611419681.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.00.00.00.00.01.00.00.00.00.01.00.0-0.0021723099052906036-0.04483500123023987-1.80666005611419681.01.00.00.00.00.01.00.00.00.00.01.00.0-0.016442900523543358-0.062392398715019226-1.86315000057220461.034db2e33-e79f-ea57-14af-c1ce9cbc63ffbind_shape_matrix0.037142097949981690.00.00.00.00.146102800965309140.00.00.00.00.032979965209960940.00.079298749566078190.01.75784003734588621.0joint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenteralt_inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.075629897415637971.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.0-0.009507000446319580.00.251107990741729741.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.0-0.015367999672889710.00.204877004027366641.01.00.00.00.00.01.00.00.00.00.01.00.00.00.00.084072902798652651.01.00.00.00.00.01.00.00.00.00.01.00.00.00.01.0670200586318971.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0359875001013278960.0-0.0253947004675865171.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.025000000372529030.00.045000001788139341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.107000999152660370.0-0.026074899360537531.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.0591681003570556640.00.0048508602194488051.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03629549965262413-0.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.036295499652624130.01899999938905239-0.0134859997779130941.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.020269699394702910.00.0053312801755964761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083006501197814940.0-0.0203639995306730271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.083787396550178530.0-0.0266884993761777881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.03427229821681976-0.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.034272298216819760.012062000110745430.00051081198034808041.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0181128997355699540.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.018112899735569954-0.0167341008782386780.0570053011178970341.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0082314396277070050.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.008231439627707005-0.037603501230478290.0562760010361671451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.073194302618503570.00.087503999471664431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.104399003088474270.00.0171787999570369721.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.150499001145362850.00.0038539199158549311.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.044901698827743530.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.04490169882774353-0.0369763001799583440.0383545011281967161.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0291581992059946060.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.029158199205994606-0.05687420070171356-0.00453078979626297951.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.00.0167011991143226620.00.0097117396071553231.0pelvis_offset0.0inverse_bind_matrix1.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.00.0267891008406877520.0-1.81913995742797851.01.18342995643615720.00.00.00.01.197600007057190.00.00.00.01.00.00.0293253995478153230.0-1.6070699691772461.01.010100007057190.00.00.00.01.04166996479034420.00.00.00.01.00.00.0155231999233365060.0-1.35596001148223881.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.15109002590179441.01.00.00.00.00.01.00.00.00.00.01.00.00.00.0-1.06701004505157471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0341983996331691740.0-1.84081995487213131.01.08107995986938480.00.00.00.01.05708003044128420.00.00.00.01.10618996620178220.00.00178911001421511170.0-1.90898001194000241.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.105210997164249420.0-1.84016001224517821.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.2208299636840820.0-0.046043299138545990.0-2.08349990844726561.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.141506999731063840.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14150699973106384-0.01899999938905239-1.82667005062103271.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.096935302019119260.0-1.82579004764556881.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117205001413822170.0-1.82045996189117431.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.117986001074314120.0-1.81412994861602781.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.151476994156837460.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.15147699415683746-0.01206200011074543-1.8209700584411621.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.016323799267411232-0.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.0-0.0163237992674112320.017114000394940376-1.51254999637603761.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.010020599700510502-0.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.00.85106402635574340.00.0100205997005105020.038457199931144714-1.5119899511337281.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.071405202150344850.0-1.9511599540710451.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.102609001100063320.0-1.88242995738983151.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.14870999753475190.0-1.86940002441406251.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.04311259835958481-0.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.043112598359584810.037815701216459274-1.90312004089355471.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.027369100600481033-0.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.08107995986938480.0-0.0273691006004810330.058165401220321655-1.86120998859405521.01.08107995986938480.00.00.00.01.08107995986938480.00.00.00.01.041350007057190.0-0.121913000941276550.0-1.78188002109527591.0 \ No newline at end of file diff --git a/indra/llappearanceutility/tests/joint-offsets.xml.output b/indra/llappearanceutility/tests/joint-offsets.xml.output new file mode 100644 index 00000000000..d0f94b8f111 --- /dev/null +++ b/indra/llappearanceutility/tests/joint-offsets.xml.output @@ -0,0 +1 @@ +skindata05bf604d-d1c0-352b-cb2f-c37caca6f542joint_namesmFaceJawmFaceRootmHeadmNeckmChestmTorsomPelvisjoint_offset0.035987500101327896118164060-0.025394700467586517333984380.0250000003725290298461914100.04500000178813934326171875000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.06702005863189697265625pelvis_offset015659a9a-f1c1-3e38-8343-2e23e9f65d20joint_namesmHeadmNeckmChestmTorsomPelvismFaceEar2RightmFaceEar1RightmFaceRootmFaceEar1LeftmFaceEar2Leftjoint_offset000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.01427059993147850036621094-0.017557399347424507141113280.05648919939994812011718750.004137559793889522552490234-0.047394301742315292358398440.089543297886848449707031250.0250000003725290298461914100.045000001788139343261718750.0041375597938895225524902340.047394301742315292358398440.089543297886848449707031250.014270599931478500366210940.017557399347424507141113280.0564891993999481201171875pelvis_offset01d5936bc-0501-7376-f70c-06dcfac920edjoint_namesmEyeLeftmHeadmNeckmChestmTorsomPelvismEyeRightjoint_offset0.090427502989768981933593750.037174601107835769653320310.0805628001689910888671875000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.09042750298976898193359375-0.037174601107835769653320310.0805628001689910888671875pelvis_offset02a30e7ec-9840-f495-daa1-2b8d0d025a78joint_namesmHeadmNeckmChestmTorsomPelvismFaceEar2RightmFaceEar1RightmFaceRootmFaceEar1LeftmFaceEar2Leftjoint_offset000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.01427059993147850036621094-0.017557399347424507141113280.05648919939994812011718750.004137559793889522552490234-0.047394301742315292358398440.089543297886848449707031250.0250000003725290298461914100.045000001788139343261718750.0041375597938895225524902340.047394301742315292358398440.089543297886848449707031250.014270599931478500366210940.017557399347424507141113280.0564891993999481201171875pelvis_offset034db2e33-e79f-ea57-14af-c1ce9cbc63ffjoint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenterjoint_offset000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.035987500101327896118164060-0.025394700467586517333984380.0250000003725290298461914100.04500000178813934326171875-0.059168100357055664062500.004850860219448804855346680.10700099915266036987304690-0.02607489936053752899169922-0.059168100357055664062500.004850860219448804855346680.03629549965262413024902344-0.01899999938905239105224609-0.013485999777913093566894530.036295499652624130249023440.01899999938905239105224609-0.01348599977791309356689453-0.0202696993947029113769531200.0053312801755964756011962890.083006501197814941406250-0.020363999530673027038574220.083787396550178527832031250-0.026688499376177787780761720.03427229821681976318359375-0.012062000110745429992675780.00051081198034808039665222170.034272298216819763183593750.012062000110745429992675780.00051081198034808039665222170.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.018112899735569953918457030.016734100878238677978515620.057005301117897033691406250.01811289973556995391845703-0.016734100878238677978515620.05700530111789703369140625-0.0082314396277070045471191410.037603501230478286743164060.05627600103616714477539062-0.008231439627707004547119141-0.037603501230478286743164060.056276001036167144775390620.0731943026185035705566406200.08750399947166442871093750.104399003088474273681640600.017178799957036972045898440.150499001145362854003906200.0038539199158549308776855470.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.029158199205994606018066410.05687420070171356201171875-0.0045307897962629795074462890.02915819920599460601806641-0.05687420070171356201171875-0.0045307897962629795074462890.0167011991143226623535156200.009711739607155323028564453pelvis_offset03bd8d73d-be6f-8de2-39ae-1f680189bc27joint_namesmHeadmNeckmChestmTorsomPelvismFaceEar2RightmFaceEar1RightmFaceRootmFaceEar1LeftmFaceEar2Leftjoint_offset000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.01427059993147850036621094-0.017557399347424507141113280.05648919939994812011718750.004137559793889522552490234-0.047394301742315292358398440.089543297886848449707031250.0250000003725290298461914100.045000001788139343261718750.0041375597938895225524902340.047394301742315292358398440.089543297886848449707031250.014270599931478500366210940.017557399347424507141113280.0564891993999481201171875pelvis_offset046ee8fb2-15f0-fa2e-d260-e7e6e8295445joint_namesmFaceJawmFaceRootmHeadmNeckmChestmTorsomPelvisjoint_offset0.035987500101327896118164060-0.025394700467586517333984380.0250000003725290298461914100.04500000178813934326171875000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.06702005863189697265625pelvis_offset0547d8392-9f19-35fb-3508-121eea388f0ajoint_namesmFaceJawmFaceRootmHeadmNeckmChestmTorsomPelvismFaceTongueBasemFaceTeethLowermFaceTongueTipjoint_offset0.035987500101327896118164060-0.025394700467586517333984380.0250000003725290298461914100.04500000178813934326171875000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.06702005863189697265625-0.0298503991216421127319335900.0078316899016499519348144530.083006501197814941406250-0.020363999530673027038574220.03891620039939880371093750-0.002775429980829358100891113pelvis_offset07e7a6834-8b41-4029-8f87-ce57b7d05beejoint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenterjoint_offset000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.035987500101327896118164060-0.025394700467586517333984380.0250000003725290298461914100.04500000178813934326171875-0.059168100357055664062500.004850860219448804855346680.10700099915266036987304690-0.02607489936053752899169922-0.059168100357055664062500.004850860219448804855346680.03629549965262413024902344-0.01899999938905239105224609-0.013485999777913093566894530.036295499652624130249023440.01899999938905239105224609-0.01348599977791309356689453-0.0202696993947029113769531200.0053312801755964756011962890.083006501197814941406250-0.020363999530673027038574220.083787396550178527832031250-0.026688499376177787780761720.03427229821681976318359375-0.012062000110745429992675780.00051081198034808039665222170.034272298216819763183593750.012062000110745429992675780.00051081198034808039665222170.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.018112899735569953918457030.016734100878238677978515620.057005301117897033691406250.01811289973556995391845703-0.016734100878238677978515620.05700530111789703369140625-0.0082314396277070045471191410.037603501230478286743164060.05627600103616714477539062-0.008231439627707004547119141-0.037603501230478286743164060.056276001036167144775390620.0731943026185035705566406200.08750399947166442871093750.104399003088474273681640600.017178799957036972045898440.150499001145362854003906200.0038539199158549308776855470.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.029158199205994606018066410.05687420070171356201171875-0.0045307897962629795074462890.02915819920599460601806641-0.05687420070171356201171875-0.0045307897962629795074462890.0167011991143226623535156200.009711739607155323028564453pelvis_offset08665c374-cb61-d418-d412-7f4ea828e119joint_namesmTail1mPelvismTail2mTail3mTail4mTail6mTail5joint_offset-0.165999993681907653808593800.0670000016689300537109375001.06702005863189697265625-0.147750005125999450683593800-0.126000002026557922363281200-0.106499999761581420898437500-0.0705000013113021850585937500-0.0839999988675117492675781200pelvis_offset08d23b8c8-fadf-c1b3-0b04-a3ecea292576joint_namesmHeadmNeckmChestmTorsomPelvismFaceEar2RightmFaceEar1RightmFaceRootmFaceEar1LeftmFaceEar2Leftjoint_offset000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.01427059993147850036621094-0.017557399347424507141113280.05648919939994812011718750.004137559793889522552490234-0.047394301742315292358398440.089543297886848449707031250.0250000003725290298461914100.045000001788139343261718750.0041375597938895225524902340.047394301742315292358398440.089543297886848449707031250.014270599931478500366210940.017557399347424507141113280.0564891993999481201171875pelvis_offset09174c7f1-bd5f-68d2-2f4f-cc9b36312067joint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenterjoint_offset000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.035987500101327896118164060-0.025396499782800674438476560.0250000003725290298461914100.04500000178813934326171875-0.059168100357055664062500.004850860219448804855346680.10700099915266036987304690-0.02607659995555877685546875-0.059168100357055664062500.004850860219448804855346680.03629549965262413024902344-0.01899999938905239105224609-0.013485999777913093566894530.036295499652624130249023440.01899999938905239105224609-0.01348599977791309356689453-0.0202696993947029113769531200.0053312801755964756011962890.083006501197814941406250-0.020363999530673027038574220.083787396550178527832031250-0.026688499376177787780761720.03427229821681976318359375-0.012062000110745429992675780.00051081198034808039665222170.034272298216819763183593750.012062000110745429992675780.00051081198034808039665222170.04490169882774353027343750.036976300179958343505859380.038352798670530319213867190.0449016988277435302734375-0.036976300179958343505859380.038352798670530319213867190.018112899735569953918457030.016734100878238677978515620.057003501802682876586914060.01811289973556995391845703-0.016734100878238677978515620.05700350180268287658691406-0.0082314396277070045471191410.037603501230478286743164060.05627429857850074768066406-0.008231439627707004547119141-0.037603501230478286743164060.056274298578500747680664060.0731943026185035705566406200.087502397596836090087890620.104399003088474273681640600.017177099362015724182128910.150499001145362854003906200.0038522500544786453247070310.04490169882774353027343750.036976300179958343505859380.038352798670530319213867190.0449016988277435302734375-0.036976300179958343505859380.038352798670530319213867190.029158199205994606018066410.05687420070171356201171875-0.0045324601233005523681640620.02915819920599460601806641-0.05687420070171356201171875-0.0045324601233005523681640620.0167011991143226623535156200.009711739607155323028564453pelvis_offset092a7dd5c-bc30-9952-3b3b-e6cc10336cbejoint_namesmEyeLeftmHeadmNeckmChestmTorsomPelvismEyeRightjoint_offset0.090427502989768981933593750.037174601107835769653320310.0805628001689910888671875000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.09042750298976898193359375-0.037174601107835769653320310.0805628001689910888671875pelvis_offset0971cf873-afce-8b69-44d6-3f5879cb94c2joint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenterjoint_offset000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.035987500101327896118164060-0.025394700467586517333984380.0250000003725290298461914100.04500000178813934326171875-0.059168100357055664062500.004850860219448804855346680.10700099915266036987304690-0.02607489936053752899169922-0.059168100357055664062500.004850860219448804855346680.03629549965262413024902344-0.01899999938905239105224609-0.013485999777913093566894530.036295499652624130249023440.01899999938905239105224609-0.01348599977791309356689453-0.0202696993947029113769531200.0053312801755964756011962890.083006501197814941406250-0.020363999530673027038574220.083787396550178527832031250-0.026688499376177787780761720.03427229821681976318359375-0.012062000110745429992675780.00051081198034808039665222170.034272298216819763183593750.012062000110745429992675780.00051081198034808039665222170.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.018112899735569953918457030.016734100878238677978515620.057005301117897033691406250.01811289973556995391845703-0.016734100878238677978515620.05700530111789703369140625-0.0082314396277070045471191410.037603501230478286743164060.05627600103616714477539062-0.008231439627707004547119141-0.037603501230478286743164060.056276001036167144775390620.0731943026185035705566406200.08750399947166442871093750.104399003088474273681640600.017178799957036972045898440.150499001145362854003906200.0038539199158549308776855470.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.029158199205994606018066410.05687420070171356201171875-0.0045307897962629795074462890.02915819920599460601806641-0.05687420070171356201171875-0.0045307897962629795074462890.0167011991143226623535156200.009711739607155323028564453pelvis_offset0d0328b82-d9ca-6071-b248-17edfc7612cbjoint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenterjoint_offset000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.035987500101327896118164060-0.025394700467586517333984380.0250000003725290298461914100.04500000178813934326171875-0.059168100357055664062500.004850860219448804855346680.10700099915266036987304690-0.02607489936053752899169922-0.059168100357055664062500.004850860219448804855346680.03629549965262413024902344-0.01899999938905239105224609-0.013485999777913093566894530.036295499652624130249023440.01899999938905239105224609-0.01348599977791309356689453-0.0202696993947029113769531200.0053312801755964756011962890.083006501197814941406250-0.020363999530673027038574220.083787396550178527832031250-0.026688499376177787780761720.03427229821681976318359375-0.012062000110745429992675780.00051081198034808039665222170.034272298216819763183593750.012062000110745429992675780.00051081198034808039665222170.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.018112899735569953918457030.016734100878238677978515620.057005301117897033691406250.01811289973556995391845703-0.016734100878238677978515620.05700530111789703369140625-0.0082314396277070045471191410.037603501230478286743164060.05627600103616714477539062-0.008231439627707004547119141-0.037603501230478286743164060.056276001036167144775390620.0731943026185035705566406200.08750399947166442871093750.104399003088474273681640600.017178799957036972045898440.150499001145362854003906200.0038539199158549308776855470.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.029158199205994606018066410.05687420070171356201171875-0.0045307897962629795074462890.02915819920599460601806641-0.05687420070171356201171875-0.0045307897962629795074462890.0167011991143226623535156200.009711739607155323028564453pelvis_offset0d2205615-2ce0-4ff1-2bfd-bdc77a3825ccjoint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenterjoint_offset000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.035987500101327896118164060-0.025394700467586517333984380.0250000003725290298461914100.04500000178813934326171875-0.059168100357055664062500.004850860219448804855346680.10700099915266036987304690-0.02607489936053752899169922-0.059168100357055664062500.004850860219448804855346680.03629549965262413024902344-0.01899999938905239105224609-0.013485999777913093566894530.036295499652624130249023440.01899999938905239105224609-0.01348599977791309356689453-0.0202696993947029113769531200.0053312801755964756011962890.083006501197814941406250-0.020363999530673027038574220.083787396550178527832031250-0.026688499376177787780761720.03427229821681976318359375-0.012062000110745429992675780.00051081198034808039665222170.034272298216819763183593750.012062000110745429992675780.00051081198034808039665222170.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.018112899735569953918457030.016734100878238677978515620.057005301117897033691406250.01811289973556995391845703-0.016734100878238677978515620.05700530111789703369140625-0.0082314396277070045471191410.037603501230478286743164060.05627600103616714477539062-0.008231439627707004547119141-0.037603501230478286743164060.056276001036167144775390620.0731943026185035705566406200.08750399947166442871093750.104399003088474273681640600.017178799957036972045898440.150499001145362854003906200.0038539199158549308776855470.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.029158199205994606018066410.05687420070171356201171875-0.0045307897962629795074462890.02915819920599460601806641-0.05687420070171356201171875-0.0045307897962629795074462890.0167011991143226623535156200.009711739607155323028564453pelvis_offset0d73dea3b-b8cb-59ff-c76b-cfdcc8119bb5joint_namesmFaceJawmFaceRootmHeadmNeckmChestmTorsomPelvisjoint_offset0.035987500101327896118164060-0.025394700467586517333984380.0250000003725290298461914100.04500000178813934326171875000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.06702005863189697265625pelvis_offset0e678576a-dc9f-5187-6ed5-5b4aafb65d7bjoint_namesmHeadmNeckmChestmTorsomPelvismFaceJawmFaceRootmFaceLipUpperLeftmFaceTeethUppermFaceLipUpperRightmFaceLipCornerLeftmFaceLipCornerRightmFaceLipLowerCentermFaceTeethLowermFaceChinmFaceLipLowerLeftmFaceLipLowerRightmFaceEyeLidUpperLeftmFaceEyeLidUpperRightmFaceEyebrowInnerLeftmFaceEyebrowInnerRightmFaceEyebrowCenterLeftmFaceEyebrowCenterRightmFaceForeheadCentermFaceNoseBridgemFaceNoseBasemFaceEyeLidLowerLeftmFaceEyeLidLowerRightmFaceCheekUpperLeftmFaceCheekUpperRightmFaceLipUpperCenterjoint_offset000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.035987500101327896118164060-0.025394700467586517333984380.0250000003725290298461914100.04500000178813934326171875-0.059168100357055664062500.004850860219448804855346680.10700099915266036987304690-0.02607489936053752899169922-0.059168100357055664062500.004850860219448804855346680.03629549965262413024902344-0.01899999938905239105224609-0.013485999777913093566894530.036295499652624130249023440.01899999938905239105224609-0.01348599977791309356689453-0.0202696993947029113769531200.0053312801755964756011962890.083006501197814941406250-0.020363999530673027038574220.083787396550178527832031250-0.026688499376177787780761720.03427229821681976318359375-0.012062000110745429992675780.00051081198034808039665222170.034272298216819763183593750.012062000110745429992675780.00051081198034808039665222170.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.018112899735569953918457030.016734100878238677978515620.057005301117897033691406250.01811289973556995391845703-0.016734100878238677978515620.05700530111789703369140625-0.0082314396277070045471191410.037603501230478286743164060.05627600103616714477539062-0.008231439627707004547119141-0.037603501230478286743164060.056276001036167144775390620.0731943026185035705566406200.08750399947166442871093750.104399003088474273681640600.017178799957036972045898440.150499001145362854003906200.0038539199158549308776855470.04490169882774353027343750.036976300179958343505859380.038354501128196716308593750.0449016988277435302734375-0.036976300179958343505859380.038354501128196716308593750.029158199205994606018066410.05687420070171356201171875-0.0045307897962629795074462890.02915819920599460601806641-0.05687420070171356201171875-0.0045307897962629795074462890.0167011991143226623535156200.009711739607155323028564453pelvis_offset0ed796a27-cff0-454a-ecec-fd10794ca2c9joint_namesmFaceNoseBasemFaceRootmHeadmNeckmChestmTorsomPelvismFaceLipUpperCentermFaceTeethUpperjoint_offset0.150499001145362854003906200.0038539199158549308776855470.0250000003725290298461914100.04500000178813934326171875000.07562989741563796997070312-0.00950700044631958007812500.251107990741729736328125-0.0153679996728897094726562500.2048770040273666381835938000.08407290279865264892578125001.067020058631896972656250.0167011991143226623535156200.0097117396071553230285644530.10700099915266036987304690-0.02607489936053752899169922pelvis_offset0fa0aabfe-4b1c-fa9b-4942-74e7e7f50fe2joint_namesmPelvismHandMiddle1LeftmHandMiddle2LeftmHandMiddle3LeftmHandIndex1LeftmHandIndex2LeftmHandIndex3LeftmHandRing1LeftmHandRing2LeftmHandRing3LeftmHandPinky1LeftmHandPinky2LeftmHandPinky3LeftmHandThumb1LeftmHandThumb2LeftmHandThumb3LeftmHandMiddle1RightmHandMiddle2RightmHandMiddle3RightmHandIndex1RightmHandIndex2RightmHandIndex3RightmHandRing1RightmHandRing2RightmHandRing3RightmHandPinky1RightmHandPinky2RightmHandPinky3RightmHandThumb1RightmHandThumb2RightmHandThumb3Rightjoint_offset001.067020058631896972656250.015188699588179588317871090.098942197859287261962890620.01042949967086315155029297-0.0010505600366741418838500980.04202070087194442749023438-0.006302990019321441650390625-0.00050425098743289709091186520.02471089921891689300537109-0.0040346500463783740997314450.034273900091648101806640620.09468069672584533691406250.0096299396827816963195800780.017191000282764434814453120.03640490025281906127929688-0.0060679200105369091033935550.010213700123131275177001950.02334530092775821685791016-0.004377489909529685974121094-0.0036476401146501302719116210.0965808033943176269531250.004405209794640541076660156-0.012315300293266773223876950.03599850088357925415039062-0.007578520104289054870605469-0.0065627098083496093750.02019299939274787902832031-0.00454388977959752082824707-0.023213399574160575866699220.08812329918146133422851562-0.004173850174993276596069336-0.022267799824476242065429690.02319590002298355102539062-0.005566920153796672821044922-0.01243670005351305007934570.01492409966886043548583984-0.0033164799679070711135864260.032215598970651626586914060.02088090032339096069335938-0.0085530597716569900512695310.029450999572873115539550780.03365840017795562744140625-0.0010520200012251734733581540.020924899727106094360351560.02820369973778724670410156-0.00090962200192734599113464360.01518869958817958831787109-0.098942197859287261962890620.01042949967086315155029297-0.001050550024956464767456055-0.04202080145478248596191406-0.006302880123257637023925781-0.0005042660050094127655029297-0.02471089921891689300537109-0.0040346598252654075622558590.03427390009164810180664062-0.09468069672584533691406250.0096299396827816963195800780.01719100028276443481445312-0.03640500083565711975097656-0.0060678198933601379394531250.01021370012313127517700195-0.02334530092775821685791016-0.004377489909529685974121094-0.003647640114650130271911621-0.0965808033943176269531250.004405209794640541076660156-0.01231530029326677322387695-0.03599840030074119567871094-0.007578390184789896011352539-0.006562769878655672073364258-0.02019290067255496978759766-0.004543649964034557342529297-0.02321339957416057586669922-0.08812329918146133422851562-0.004173850174993276596069336-0.02226779982447624206542969-0.02319570071995258331298828-0.005566900130361318588256836-0.01243660040199756622314453-0.01492400001734495162963867-0.0033167300280183553695678710.03221559897065162658691406-0.02088090032339096069335938-0.0085530597716569900512695310.02945090085268020629882812-0.03365840017795562744140625-0.0010520999785512685775756840.02092500030994415283203125-0.02820380032062530517578125-0.0009097899892367422580718994pelvis_offset0success1 diff --git a/indra/llappearanceutility/tests/params.xml b/indra/llappearanceutility/tests/params.xml new file mode 100644 index 00000000000..7d7ff646b7d --- /dev/null +++ b/indra/llappearanceutility/tests/params.xml @@ -0,0 +1,1140 @@ + + + + skindata + + 270bb701-8643-c4b3-6a93-7a2b6503b30a + + joint_names + + mTail1 + mPelvis + mTail2 + mTorso + mSpine2 + mSpine1 + mHipLeft + mKneeLeft + mHipRight + mKneeRight + mChest + mSpine4 + mSpine3 + mShoulderRight + mCollarRight + mShoulderLeft + mCollarLeft + mElbowRight + mElbowLeft + mNeck + mAnkleRight + mAnkleLeft + + joint_offset + + + -0.12795400619506836 + 0.0 + 0.001858999952673912 + + + 0.0 + 0.0 + 1.081987977027893 + + + -0.018850000575184822 + 0.0 + -0.09493499994277954 + + + 0.0 + 0.0 + 0.08407299965620041 + + + 0.0 + 0.0 + -0.08407299965620041 + + + 0.0 + 0.0 + 0.08407299965620041 + + + 0.03375700116157532 + 0.12676499783992767 + -0.04099800065159798 + + + -0.0008870000019669533 + -0.04556800052523613 + -0.4910529851913452 + + + 0.03361999988555908 + -0.1288059949874878 + -0.041085999459028244 + + + -0.0007800000021234155 + 0.04863499850034714 + -0.4909220039844513 + + + -0.01536799967288971 + 0.0 + 0.20487700402736664 + + + 0.01536799967288971 + 0.0 + -0.20487700402736664 + + + -0.01536799967288971 + 0.0 + 0.20487700402736664 + + + 0.0 + -0.07941800355911255 + 0.0 + + + -0.020927000790834427 + -0.08500000089406967 + 0.16539600491523743 + + + 0.0 + 0.07900000363588333 + 0.0 + + + -0.020927000790834427 + 0.08466500043869019 + 0.16539600491523743 + + + 0.0 + -0.24799999594688416 + 0.0 + + + 0.0 + 0.24799999594688416 + 0.0 + + + -0.00950700044631958 + 0.0 + 0.25110799074172974 + + + -0.02886899933218956 + 0.0 + -0.4684939980506897 + + + -0.028886999934911728 + 0.0013780000153928995 + -0.4684489965438843 + + + pelvis_offset + 0.0 + + + wearables + + + + agent_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + asset_id + 7e3e76fc-7fa4-ec8f-a785-8956dbce6e72 + contents + LLWearable version 22 +Fashionista Male - Shape (new) + + permissions 0 + { + base_mask 7fffffff + owner_mask 7fffffff + group_mask 00000000 + everyone_mask 00000000 + next_owner_mask 00082000 + creator_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + owner_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + last_owner_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + group_id 00000000-0000-0000-0000-000000000000 + } + sale_info 0 + { + sale_type not + sale_price 10 + } +type 0 +parameters 142 +1 0 +2 .16 +4 -.23 +5 -.1 +6 -.3 +7 0 +8 0 +10 0 +11 .04 +12 0 +13 0 +14 0 +15 0 +17 0 +18 0 +19 -.1 +20 .56 +21 .07 +22 0 +23 .42 +24 -.66 +25 .51 +26 0 +27 .02 +28 .6 +29 0 +30 0 +32 1 +33 -.41 +34 .4 +35 0 +36 -.49 +37 0 +38 .42 +40 1 +80 1 +100 1 +104 0 +105 .5 +106 0 +107 0 +151 .16 +152 0 +153 1 +155 -.13 +156 0 +157 0 +185 -.44 +186 0 +187 0 +188 0 +189 0 +193 .5 +194 -.12 +195 -.06 +196 -.59 +505 .65 +506 -.04 +507 0 +515 -.2 +517 .12 +518 -.3 +626 0 +627 0 +629 .5 +630 0 +631 0 +633 .01 +634 .01 +635 .01 +637 .01 +646 0 +647 0 +648 0 +649 .5 +650 -.67 +651 .03 +652 .49 +653 .26 +655 -.08 +656 0 +657 .03 +658 0 +659 .51 +660 0 +661 0 +662 .5 +663 -.2 +664 .13 +665 .04 +675 .03 +676 -.43 +677 .34 +678 .37 +679 -.08 +680 -.08 +681 -.08 +682 .5 +683 -.14 +684 0 +685 .14 +686 -.68 +687 -.09 +688 -.09 +689 -.34 +690 .33 +691 -.09 +692 .24 +693 .1 +694 -.08 +695 -.09 +753 .06 +756 -.08 +758 -1.05 +759 .67 +760 0 +764 -.5 +765 1.02 +767 .08 +768 .08 +769 .52 +770 0 +772 0 +773 .5 +794 0 +795 .41 +796 0 +797 .15 +798 0 +799 .45 +841 0 +842 -.8 +843 0 +853 0 +854 .06 +855 -.43 +879 -.1 +880 -.82 +1103 0 +1104 0 +1105 0 +11001 0 +textures 0 + + created_at + 1724256027 + desc + + flags + 256 + inv_type + 18 + item_id + 8bbf11b0-b86b-3b4c-8c5c-c84902425f42 + metadata + + + name + Leonard - Shape + parent_id + 056f26cf-a9d9-39b9-a90c-f7b0fcd92347 + permissions + + base_mask + 573440 + creator_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + everyone_mask + 524288 + group_id + 00000000-0000-0000-0000-000000000000 + group_mask + 540672 + last_owner_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + next_owner_mask + 573440 + owner_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + owner_mask + 573440 + + sale_info + + sale_price + 10 + sale_type + 0 + + type + 13 + wearable_type + 0 + + + + + agent_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + asset_id + 9e675544-77c0-0db6-3694-462be7460b76 + contents + LLWearable version 22 +Formal Male - Skin (less old) + + permissions 0 + { + base_mask 7fffffff + owner_mask 7fffffff + group_mask 00000000 + everyone_mask 00000000 + next_owner_mask 00082000 + creator_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + owner_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + last_owner_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + group_id 00000000-0000-0000-0000-000000000000 + } + sale_info 0 + { + sale_type not + sale_price 10 + } +type 1 +parameters 37 +108 0 +110 0 +111 0 +116 0 +117 0 +118 0 +125 0 +126 0 +150 0 +158 0 +159 0 +161 0 +162 0 +163 0 +165 0 +700 .25 +701 0 +702 0 +703 0 +704 0 +705 .5 +706 .6 +707 0 +708 0 +709 0 +710 0 +711 .5 +712 0 +713 .7 +714 0 +715 0 +775 0 +776 0 +777 0 +873 0 +874 0 +878 0 +textures 3 +0 a21d4081-601e-f9f0-0acc-9192c72863dc +5 a85bf749-952d-3835-d9ac-a307c780930c +6 ab169525-d46c-918b-3195-7f2b92fd76c5 + + created_at + 1724256027 + desc + + flags + 257 + inv_type + 18 + item_id + 9e6c5696-cae0-337e-a5c6-aa6fede08ec6 + metadata + + + name + Leonard - Skin + parent_id + 056f26cf-a9d9-39b9-a90c-f7b0fcd92347 + permissions + + base_mask + 557056 + creator_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + everyone_mask + 524288 + group_id + 00000000-0000-0000-0000-000000000000 + group_mask + 524288 + last_owner_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + next_owner_mask + 557056 + owner_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + owner_mask + 557056 + + sale_info + + sale_price + 10 + sale_type + 0 + + type + 13 + wearable_type + 1 + + + + + agent_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + asset_id + 0b935621-92da-099e-a248-cfbfa3624c68 + contents + LLWearable version 22 +Fashionista Male - Brows (new) + + permissions 0 + { + base_mask 00082000 + owner_mask 00082000 + group_mask 00000000 + everyone_mask 00000000 + next_owner_mask 00082000 + creator_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + owner_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + last_owner_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + group_id 00000000-0000-0000-0000-000000000000 + } + sale_info 0 + { + sale_type not + sale_price 10 + } +type 2 +parameters 90 +16 .41 +31 1.04 +112 0 +113 0 +114 0 +115 0 +119 .5 +130 0 +131 0 +132 0 +133 0 +134 0 +135 0 +136 0 +137 .5 +140 0 +141 0 +142 0 +143 -4 +144 1 +145 0 +146 1 +147 0 +148 1 +149 0 +166 0 +167 0 +168 0 +169 0 +171 0 +172 1 +173 0 +174 1 +175 0 +176 1 +177 0 +178 0 +179 1 +180 0 +181 -1 +182 -1 +183 -1 +184 0 +190 0 +191 0 +192 0 +400 .75 +640 -.01 +641 .2 +642 0 +643 0 +644 .24 +645 0 +674 -.3 +750 .65 +751 0 +752 .5 +754 0 +755 .05 +757 -1.6 +761 1.3 +762 0 +763 0 +771 -.08 +774 0 +782 0 +783 0 +784 0 +785 0 +786 0 +787 0 +788 0 +789 0 +790 0 +870 -.11 +871 -.4 +872 .52 +1000 .5 +1001 .5 +1002 .65 +1003 .65 +1004 0 +1005 0 +1006 0 +1007 0 +1008 0 +1009 0 +1010 0 +1011 0 +1012 .25 +textures 1 +4 3cc3add8-6ff0-0640-79ba-b15137f64008 + + created_at + 1724256027 + desc + + flags + 258 + inv_type + 18 + item_id + 3ddd2d41-fbe4-3076-9732-c5f3b12973b1 + metadata + + + name + Leonard - Brows + parent_id + 056f26cf-a9d9-39b9-a90c-f7b0fcd92347 + permissions + + base_mask + 557056 + creator_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + everyone_mask + 524288 + group_id + 00000000-0000-0000-0000-000000000000 + group_mask + 524288 + last_owner_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + next_owner_mask + 557056 + owner_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + owner_mask + 557056 + + sale_info + + sale_price + 10 + sale_type + 0 + + type + 13 + wearable_type + 2 + + + + + agent_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + asset_id + 052ca46d-9612-7a43-25a9-d7c8a5387cf6 + contents + LLWearable version 22 +Fashionista Male - Eyes + + permissions 0 + { + base_mask 7fffffff + owner_mask 7fffffff + group_mask 00000000 + everyone_mask 00000000 + next_owner_mask 00082000 + creator_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + owner_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + last_owner_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + group_id 00000000-0000-0000-0000-000000000000 + } + sale_info 0 + { + sale_type not + sale_price 10 + } +type 3 +parameters 2 +98 1 +99 0 +textures 1 +3 579e320c-0f16-2a1d-2018-2a00cc657068 + + created_at + 1724256027 + desc + + flags + 259 + inv_type + 18 + item_id + 9d4e7072-0e92-39a1-95a4-b5330450b1ee + metadata + + + name + Leonard - Eyes + parent_id + 056f26cf-a9d9-39b9-a90c-f7b0fcd92347 + permissions + + base_mask + 557056 + creator_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + everyone_mask + 524288 + group_id + 00000000-0000-0000-0000-000000000000 + group_mask + 524288 + last_owner_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + next_owner_mask + 557056 + owner_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + owner_mask + 557056 + + sale_info + + sale_price + 10 + sale_type + 0 + + type + 13 + wearable_type + 3 + + + + + + + + + agent_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + asset_id + 5f049939-bb34-ad27-66cb-38c9151a105d + contents + LLWearable version 22 +Fashionista Male - Shoe Base + + permissions 0 + { + base_mask 7fffffff + owner_mask 7fffffff + group_mask 00000000 + everyone_mask 00000000 + next_owner_mask 00082000 + creator_id 73ecef5a-3110-4e95-92bc-da0ae7598652 + owner_id 73ecef5a-3110-4e95-92bc-da0ae7598652 + last_owner_id 73ecef5a-3110-4e95-92bc-da0ae7598652 + group_id 00000000-0000-0000-0000-000000000000 + } + sale_info 0 + { + sale_type not + sale_price 10 + } +type 6 +parameters 20 +197 0 +198 0 +500 0 +501 .1 +502 .1 +503 .1 +508 -.52 +509 1 +510 0 +511 .82 +512 0 +513 0 +514 .09 +616 .3 +654 .06 +812 1 +813 1 +817 1 +1052 .3 +1053 .3 +textures 1 +7 8dcd4a48-2d37-4909-9f78-f7a9eb4ef903 + + created_at + 1724256027 + desc + @600 + flags + 262 + inv_type + 18 + item_id + dc5e279a-4a34-36ee-9075-028df446392c + metadata + + + name + Leonard - Shoes BASE + parent_id + 056f26cf-a9d9-39b9-a90c-f7b0fcd92347 + permissions + + base_mask + 557056 + creator_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + everyone_mask + 524288 + group_id + 00000000-0000-0000-0000-000000000000 + group_mask + 524288 + last_owner_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + next_owner_mask + 557056 + owner_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + owner_mask + 557056 + + sale_info + + sale_price + 10 + sale_type + 0 + + type + 5 + wearable_type + 6 + + + + + + + + + + + + + + + + + agent_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + asset_id + ab0bd2c6-3776-7ea6-264f-102842c6328b + contents + LLWearable version 22 +Fashionista Female - Heels Alpha + + permissions 0 + { + base_mask 7fffffff + owner_mask 7fffffff + group_mask 00000000 + everyone_mask 00000000 + next_owner_mask 00082000 + creator_id 73ecef5a-3110-4e95-92bc-da0ae7598652 + owner_id 73ecef5a-3110-4e95-92bc-da0ae7598652 + last_owner_id 73ecef5a-3110-4e95-92bc-da0ae7598652 + group_id 00000000-0000-0000-0000-000000000000 + } + sale_info 0 + { + sale_type not + sale_price 10 + } +type 13 +parameters 0 +textures 5 +21 b5b09502-8305-af43-cc4e-7238cb715b11 +22 5748decc-f629-461c-9a36-a35a221fe21f +23 5748decc-f629-461c-9a36-a35a221fe21f +24 5748decc-f629-461c-9a36-a35a221fe21f +25 5748decc-f629-461c-9a36-a35a221fe21f + + created_at + 1724256027 + desc + @1300 + flags + 269 + inv_type + 18 + item_id + b76dde5f-0da2-3e21-b505-d587b16ddb3c + metadata + + + name + Leonard - Shoes ALPHA + parent_id + 056f26cf-a9d9-39b9-a90c-f7b0fcd92347 + permissions + + base_mask + 557056 + creator_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + everyone_mask + 524288 + group_id + 00000000-0000-0000-0000-000000000000 + group_mask + 524288 + last_owner_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + next_owner_mask + 557056 + owner_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + owner_mask + 557056 + + sale_info + + sale_price + 10 + sale_type + 0 + + type + 5 + wearable_type + 13 + + + agent_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + asset_id + cb80f44f-8265-f56b-c812-ddf729cee73b + contents + LLWearable version 22 +New Alpha + + permissions 0 + { + base_mask 7fffffff + owner_mask 7fffffff + group_mask 00000000 + everyone_mask 00000000 + next_owner_mask 00082000 + creator_id 8b1453d6-ec45-4434-bee3-1c4d6fe1bc55 + owner_id 8b1453d6-ec45-4434-bee3-1c4d6fe1bc55 + last_owner_id 8b1453d6-ec45-4434-bee3-1c4d6fe1bc55 + group_id 00000000-0000-0000-0000-000000000000 + } + sale_info 0 + { + sale_type not + sale_price 10 + } +type 13 +parameters 0 +textures 5 +21 d9413239-769d-abc9-e929-4fa98f52c07b +22 b5d465f9-ca8e-8ba4-efd8-ee8929c592b8 +23 5748decc-f629-461c-9a36-a35a221fe21f +24 5748decc-f629-461c-9a36-a35a221fe21f +25 5748decc-f629-461c-9a36-a35a221fe21f + + created_at + 1724256027 + desc + @1301 + flags + 269 + inv_type + 18 + item_id + efc7da55-02ba-3286-8458-780aede51b49 + metadata + + + name + Leonard - Suit Alpha + parent_id + 056f26cf-a9d9-39b9-a90c-f7b0fcd92347 + permissions + + base_mask + 557056 + creator_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + everyone_mask + 524288 + group_id + 00000000-0000-0000-0000-000000000000 + group_mask + 524288 + last_owner_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + next_owner_mask + 557056 + owner_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + owner_mask + 557056 + + sale_info + + sale_price + 10 + sale_type + 0 + + type + 5 + wearable_type + 13 + + + agent_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + asset_id + f235a6a9-062a-bb40-46c2-c8a7bec95fbf + contents + LLWearable version 22 +System Eyelash Remover + + permissions 0 + { + base_mask 7fffffff + owner_mask 7fffffff + group_mask 00000000 + everyone_mask 00000000 + next_owner_mask 00082000 + creator_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + owner_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + last_owner_id 1f8f7642-ce98-4d1b-9314-e2bc98b6538d + group_id 00000000-0000-0000-0000-000000000000 + } + sale_info 0 + { + sale_type not + sale_price 10 + } +type 13 +parameters 0 +textures 5 +21 5748decc-f629-461c-9a36-a35a221fe21f +22 5748decc-f629-461c-9a36-a35a221fe21f +23 9e460914-daed-b03f-0f2a-afbe67833b11 +24 5748decc-f629-461c-9a36-a35a221fe21f +25 5748decc-f629-461c-9a36-a35a221fe21f + + created_at + 1724256027 + desc + @1302 + flags + 269 + inv_type + 18 + item_id + 624f9c12-72e8-3409-a3f3-b3fe8f496b13 + metadata + + + name + System Eyelash Remover + parent_id + 056f26cf-a9d9-39b9-a90c-f7b0fcd92347 + permissions + + base_mask + 557056 + creator_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + everyone_mask + 524288 + group_id + 00000000-0000-0000-0000-000000000000 + group_mask + 524288 + last_owner_id + ba2a564a-f0f1-4b82-9c61-b7520bfcd09f + next_owner_mask + 557056 + owner_id + de494a4f-f01a-47a4-98cf-c94ef9ecca38 + owner_mask + 557056 + + sale_info + + sale_price + 10 + sale_type + 0 + + type + 5 + wearable_type + 13 + + + + + + + + + + + diff --git a/indra/llappearanceutility/tests/params.xml.output b/indra/llappearanceutility/tests/params.xml.output new file mode 100644 index 00000000000..58449dd37ac --- /dev/null +++ b/indra/llappearanceutility/tests/params.xml.output @@ -0,0 +1 @@ +avatar_scale0.4499999880790710449218750.600000023841857910156251.76146829128265380859375debug_params1namebig_browvalue0weight3310namesunken_cheeksvalue0weight8510000namebreast_physics_massvalue0.1000000014901161193847656weight010001namebreast_physics_gravityvalue0weight010002namebreast_physics_dragvalue1weight2510003namebreast_physics_updown_max_effectvalue0weight010004namebreast_physics_updown_springvalue10weight2510005namebreast_physics_updown_gainvalue10weight2310006namebreast_physics_updown_dampingvalue0.2000000029802322387695312weight5110007namebreast_physics_inout_max_effectvalue0weight010008namebreast_physics_inout_springvalue10weight2510009namebreast_physics_inout_gainvalue10weight2310010namebreast_physics_inout_dampingvalue0.2000000029802322387695312weight5110011namebelly_physics_massvalue0.1000000014901161193847656weight010012namebelly_physics_gravityvalue0weight010013namebelly_physics_dragvalue1weight2510014namebelly_physics_updown_max_effectvalue0weight010015namebelly_physics_updown_springvalue10weight2510016namebelly_physics_updown_gainvalue10weight2310017namebelly_physics_updown_dampingvalue0.2000000029802322387695312weight5110018namebutt_physics_massvalue0.1000000014901161193847656weight010019namebutt_physics_gravityvalue0weight010020namebutt_physics_dragvalue1weight2510021namebutt_physics_updown_max_effectvalue0weight010022namebutt_physics_updown_springvalue10weight2510023namebutt_physics_updown_gainvalue10weight2310024namebutt_physics_updown_dampingvalue0.2000000029802322387695312weight5110025namebutt_physics_leftright_max_effectvalue0weight010026namebutt_physics_leftright_springvalue10weight2510027namebutt_physics_leftright_gainvalue10weight2310028namebutt_physics_leftright_dampingvalue0.2000000029802322387695312weight5110029namebreast_physics_leftright_max_effectvalue0weight010030namebreast_physics_leftright_springvalue10weight2510031namebreast_physics_leftright_gainvalue10weight2310032namebreast_physics_leftright_dampingvalue0.2000000029802322387695312weight51105namebreast sizevalue0.5weight127108namerainbow colorvalue0weight011namenoble_nose_bridgevalue0.03999999910593032836914062weight68110namered skinvalue0weight011000nameappearancemessage_versionvalue1weight111001namehovervalue0weight127111namepigmentvalue0weight0112namerainbow colorvalue0weight0113namered hairvalue0weight0114nameblonde hairvalue0weight0115namewhite hairvalue0weight0116namerosy complexionvalue0weight0117namelip pinknessvalue0weight0119nameeyebrow sizevalue0.5weight12712namejowlsvalue0weight4213namecleft_chin_uppervalue0weight0130namefront fringevalue0weight0131nameside fringevalue0weight0132nameback fringevalue0weight0133namehair frontvalue0weight0134namehair sidesvalue0weight0135namehair backvalue0weight0136namehair sweepvalue0weight0137namehair tiltvalue0.5weight12714namehigh_cheek_bonesvalue0weight85140namehair_part_middlevalue0weight0141namehair_part_rightvalue0weight0142namehair_part_leftvalue0weight0143namehair_sides_fullvalue-4weight015nameears_outvalue0weight63150namebody definitionvalue0weight0155namelip widthvalue-0.12999999523162841796875weight89157namebelly sizevalue0weight016namepointy_eyebrowsvalue0.4099999964237213134765625weight66162namefacial definitionvalue0weight0163namewrinklesvalue0weight0165namefrecklesvalue0weight0166namesideburnsvalue0weight0167namemoustachevalue0weight0168namesoulpatchvalue0weight0169namechin curtainsvalue0weight017namesquare_jawvalue0weight85177namehair_rumpledvalue0weight018namepuffy_upper_cheeksvalue0weight95181namehair_big_frontvalue-1weight0182namehair_big_topvalue-1weight0183namehair_big_backvalue-1weight0184namehair_spikedvalue0weight0185namedeep_chinvalue-0.439999997615814208984375weight7119nameupturned_nose_tipvalue-0.1000000014901161193847656weight142192namebangs_part_middlevalue0weight0193namehead shapevalue0.5weight127196nameeye spacingvalue-0.589999973773956298828125weight119198nameheel heightvalue0weight02namenose_big_outvalue0.1599999964237213134765625weight7420namebulbous_nosevalue0.560000002384185791015625weight13521nameupper_eyelid_foldvalue0.07000000029802322387695312weight4522nameattached_earlobesvalue0weight023namebaggy_eyesvalue0.4199999868869781494140625weight11724namewide_eyesvalue-0.660000026226043701171875weight6125namewide_lip_cleftvalue0.5099999904632568359375weight14527namewide_nose_bridgevalue0.01999999955296516418457031weight13431namearced_eyebrowsvalue1.03999996185302734375weight13233nameheightvalue-0.4099999964237213134765625weight11234namethicknessvalue0.4000000059604644775390625weight12735namebig_earsvalue0weight8536nameshouldersvalue-0.4900000095367431640625weight10437namehip widthvalue0weight13638nametorso lengthvalue0.4199999868869781494140625weight1814namebroad_nostrilsvalue-0.2300000041723251342773438weight455namecleft_chinvalue-0.1000000014901161193847656weight0503nameplatform heightvalue0.1000000014901161193847656weight25505namelip thicknessvalue0.64999997615814208984375weight165506namemouth_heightvalue-0.03999999910593032836914062weight124507namebreast_gravityvalue0weight109508nameshoe_platform_widthvalue-0.519999980926513671875weight40513nameheel shapevalue0weight0514nametoe shapevalue0.0900000035762786865234375weight22515namefoot_sizevalue-0.2000000029802322387695312weight51517namewide_nosevalue0.1199999973177909851074219weight105518nameeyelashes_longvalue-0.300000011920928955078125weight06namebulbous_nose_tipvalue-0.300000011920928955078125weight0603namesleeve lengthvalue0.4000000059604644775390625weight100604namebottomvalue0.85000002384185791015625weight216605namecollar frontvalue0.839999973773956298828125weight214606namesleeve lengthvalue0.800000011920928955078125weight204607namecollar frontvalue0.800000011920928955078125weight204608namebottom length lowervalue0.800000011920928955078125weight204609nameopen jacketvalue0.2000000029802322387695312weight51616nameshoe heightvalue0.300000011920928955078125weight76617namesocks lengthvalue0.3499999940395355224609375weight89619namepants lengthvalue0.300000011920928955078125weight76624namepants waistvalue0.800000011920928955078125weight204625nameleg_pantflairvalue0weight0629nameforehead anglevalue0.5weight127637namebody fatvalue0.009999999776482582092285156weight2638namelow_crotchvalue0weight0646nameegg_headvalue0weight144647namesquash_stretch_headvalue0weight85649nametorso musclesvalue0.5weight127650nameeyelid_corner_upvalue-0.670000016689300537109375weight64652nameleg musclesvalue0.4900000095367431640625weight124653nametall_lipsvalue0.2599999904632568359375weight107654nameshoe_toe_thickvalue0.05999999865889549255371094weight7656namecrooked_nosevalue0weight127659namemouth cornervalue0.5099999904632568359375weight130662nameface shearvalue0.5weight127663nameshift_mouthvalue-0.2000000029802322387695312weight114664namepop_eyevalue0.12999999523162841796875weight140665namejaw_jutvalue0.03999999910593032836914062weight130674namehair_shear_backvalue-0.300000011920928955078125weight59675namehand sizevalue0.02999999932944774627685547weight140676namelove_handlesvalue-0.430000007152557373046875weight48678nametorso musclesvalue0.37000000476837158203125weight94682namehead sizevalue0.5weight127683nameneck thicknessvalue-0.1400000005960464477539062weight110684namebreast_female_cleavagevalue0weight47685namechest_male_no_pecsvalue0.1400000005960464477539062weight101690nameeye sizevalue0.3300000131130218505859375weight84692nameleg lengthvalue0.2399999946355819702148438weight158693namearm lengthvalue0.1000000014901161193847656weight1407nameweak_chinvalue0weight127700namelipstick colorvalue0.25weight63701namelipstickvalue0weight0702namelipglossvalue0weight0703nameeyelinervalue0weight0704nameblushvalue0weight0705nameblush colorvalue0.5weight127706nameout shdw opacityvalue0.60000002384185791015625weight127707nameouter shadowvalue0weight0708nameout shdw colorvalue0weight0709nameinner shadowvalue0weight0710namenail polishvalue0weight0711nameblush opacityvalue0.5weight127712namein shdw colorvalue0weight0713namein shdw opacityvalue0.699999988079071044921875weight159714nameeyeliner colorvalue0weight0715namenail polish colorvalue0weight0750nameeyebrow densityvalue0.64999997615814208984375weight165752namehair thicknessvalue0.5weight127753namesaddlebagsvalue0.05999999865889549255371094weight40754namehair_taper_backvalue0weight85755namehair_taper_frontvalue0.05000000074505805969238281weight131756nameneck lengthvalue-0.07999999821186065673828125weight117757namelower_eyebrowsvalue-1.60000002384185791015625weight102758namelower_bridge_nosevalue-1.0499999523162841796875weight38759namelow_septum_nosevalue0.670000016689300537109375weight170760namejaw_anglevalue0weight95762namehair_shear_frontvalue0weight0763namehair volumevalue0weight0764namelip_cleft_deepvalue-0.5weight0765namepuffy_lower_lidsvalue1.019999980926513671875weight120769nameeye depthvalue0.519999980926513671875weight132773namehead lengthvalue0.5weight127775namebody frecklesvalue0weight0779namecollar backvalue0.839999973773956298828125weight214780namecollar backvalue0.800000011920928955078125weight204781namecollar backvalue0.7799999713897705078125weight198785namepigtailsvalue0weight0789nameponytailvalue0weight0795namebutt sizevalue0.4099999964237213134765625weight104796namepointy_earsvalue0weight30799namelip ratiovalue0.449999988079071044921875weight1148namedouble_chinvalue0weight6380namemalevalue1weight255800namesleeve lengthvalue0.88999998569488525390625weight226801nameshirt bottomvalue1weight255802namecollar frontvalue0.7799999713897705078125weight198803nameshirt_redvalue1weight255804nameshirt_greenvalue1weight255805nameshirt_bluevalue1weight255806namepants_redvalue1weight255807namepants_greenvalue1weight255808namepants_bluevalue1weight255812nameshoes_redvalue1weight255813nameshoes_greenvalue1weight255814namewaist heightvalue1weight255815namepants lengthvalue0.800000011920928955078125weight204816nameloose lower clothingvalue0weight0817nameshoes_bluevalue1weight255818namesocks_redvalue1weight255819namesocks_greenvalue1weight255820namesocks_bluevalue1weight255821nameundershirt_redvalue1weight255822nameundershirt_greenvalue1weight255823nameundershirt_bluevalue1weight255824nameunderpants_redvalue1weight255825nameunderpants_greenvalue1weight255826nameunderpants_bluevalue1weight255827namegloves_redvalue1weight255828nameloose upper clothingvalue0weight0829namegloves_greenvalue1weight255830namegloves_bluevalue1weight255834namejacket_redvalue1weight255835namejacket_greenvalue1weight255836namejacket_bluevalue1weight255840nameshirtsleeve_flairvalue0weight0841namebowed_legsvalue0weight127842namehip lengthvalue-0.800000011920928955078125weight25844nameglove fingersvalue1weight255848nameskirt_bustlevalue0.2000000029802322387695312weight25858nameskirt lengthvalue0.4000000059604644775390625weight100859nameslit frontvalue1weight255860nameslit backvalue1weight255861nameslit leftvalue1weight255862nameslit rightvalue1weight255863nameskirt_loosenessvalue0.333000004291534423828125weight84868nameshirt wrinklesvalue0weight0869namepants wrinklesvalue0weight0877namejacket wrinklesvalue0weight0879namemale_packagevalue-0.1000000014901161193847656weight40880nameeyelid_inner_corner_upvalue-0.819999992847442626953125weight48921nameskirt_redvalue1weight255922nameskirt_greenvalue1weight255923nameskirt_bluevalue1weight25593nameglove lengthvalue0.800000011920928955078125weight20398nameeye lightnessvalue1weight25599nameeye colorvalue0weight0dump_joint_offsetsmesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemPelvispos001.08198797702789306640625mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemSpine1pos000.08407299965620040893554688mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemSpine2pos00-0.08407299965620040893554688mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemTorsopos000.08407299965620040893554688mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemSpine3pos-0.0153679996728897094726562500.2048770040273666381835938mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemSpine4pos0.015367999672889709472656250-0.2048770040273666381835938mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemChestpos-0.0153679996728897094726562500.2048770040273666381835938mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemNeckpos-0.00950700044631958007812500.251107990741729736328125mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemCollarLeftpos-0.020927000790834426879882810.0846650004386901855468750.1653960049152374267578125mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemShoulderLeftpos00.079000003635883331298828120mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemElbowLeftpos00.24799999594688415527343750mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemCollarRightpos-0.02092700079083442687988281-0.085000000894069671630859380.1653960049152374267578125mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemShoulderRightpos0-0.0794180035591125488281250mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemElbowRightpos0-0.24799999594688415527343750mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemHipRightpos0.03361999988555908203125-0.12880599498748779296875-0.04108599945902824401855469mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemKneeRightpos-0.0007800000021234154701232910.04863499850034713745117188-0.4909220039844512939453125mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemAnkleRightpos-0.028868999332189559936523440-0.468493998050689697265625mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemHipLeftpos0.03375700116157531738281250.1267649978399276733398438-0.04099800065159797668457031mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemKneeLeftpos-0.0008870000019669532775878906-0.04556800052523612976074219-0.49105298519134521484375mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemAnkleLeftpos-0.028886999934911727905273440.001378000015392899513244629-0.46844899654388427734375mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemTail1pos-0.12795400619506835937500.001858999952673912048339844mesh_id270bb701-8643-c4b3-6a93-7a2b6503b30anamemTail2pos-0.018850000575184822082519530-0.094934999942779541015625params3374450012763856842085636685951421354501176114513413211212785104136181255203255012700000000012700000001270000089000000000000071012711902516512410940022511050100216214204204204517689762040127201448512764124107712713012711414013059140489412711047101841581406300001271270000127015900165127408513111710238170950001201321270214204198001043011422625519825525525525525525525525525520402552552552552552552552552552552550255255255255255012725255251002552552552558400040482552552550025025235102523510025025235100250252351025235102523511127slot_texturesaux1hash_idc228d1cf-4b5d-4ba8-84f4-899a0796aa97texture_idsaux2hash_idc228d1cf-4b5d-4ba8-84f4-899a0796aa97texture_idsaux3hash_idc228d1cf-4b5d-4ba8-84f4-899a0796aa97texture_idseyeshash_id812bffac-704c-d4bb-487d-0674ccbd5d9dtexture_ids5748decc-f629-461c-9a36-a35a221fe21f579e320c-0f16-2a1d-2018-2a00cc657068hairhash_idfc7ad735-99b6-aaf1-a1bf-676ea304b624texture_ids3cc3add8-6ff0-0640-79ba-b15137f640085748decc-f629-461c-9a36-a35a221fe21fheadhash_id799f44a9-82ec-78bd-7800-3e17367229fatexture_ids5748decc-f629-461c-9a36-a35a221fe21f9e460914-daed-b03f-0f2a-afbe67833b11a21d4081-601e-f9f0-0acc-9192c72863dcleftarmhash_idc228d1cf-4b5d-4ba8-84f4-899a0796aa97texture_idsleftleghash_idc228d1cf-4b5d-4ba8-84f4-899a0796aa97texture_idslowerhash_id6d752c11-c33a-43c4-8631-3f8a6722ba59texture_ids5748decc-f629-461c-9a36-a35a221fe21f8dcd4a48-2d37-4909-9f78-f7a9eb4ef903ab169525-d46c-918b-3195-7f2b92fd76c5b5b09502-8305-af43-cc4e-7238cb715b11d9413239-769d-abc9-e929-4fa98f52c07bskirthash_idc228d1cf-4b5d-4ba8-84f4-899a0796aa97texture_idsupperhash_id5b4d5c23-3073-26d1-8d68-78d5bfa308e4texture_ids5748decc-f629-461c-9a36-a35a221fe21fa85bf749-952d-3835-d9ac-a307c780930cb5d465f9-ca8e-8ba4-efd8-ee8929c592b8success1 diff --git a/indra/llappearanceutility/tests/texture.llsd.binary b/indra/llappearanceutility/tests/texture.llsd.binary new file mode 100644 index 00000000000..6b4f34831c6 Binary files /dev/null and b/indra/llappearanceutility/tests/texture.llsd.binary differ diff --git a/indra/llappearanceutility/tests/texture.llsd.output b/indra/llappearanceutility/tests/texture.llsd.output new file mode 100644 index 00000000000..6c7690decc7 Binary files /dev/null and b/indra/llappearanceutility/tests/texture.llsd.output differ diff --git a/indra/llcommon/classic_callback.h b/indra/llcommon/classic_callback.h index 009c25d67c4..8a6ac7f7ffc 100644 --- a/indra/llcommon/classic_callback.h +++ b/indra/llcommon/classic_callback.h @@ -184,8 +184,8 @@ class ClassicCallback template auto makeClassicCallback(CALLABLE&& callable) { - return std::move(ClassicCallback - (std::forward(callable))); + return ClassicCallback + (std::forward(callable)); } /***************************************************************************** diff --git a/indra/llcommon/llatomic.cpp b/indra/llcommon/llatomic.cpp index d200bb04067..cff5e01225c 100644 --- a/indra/llcommon/llatomic.cpp +++ b/indra/llcommon/llatomic.cpp @@ -23,6 +23,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llatomic.h" //============================================================================ diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 3d5d30bd90a..8fb7823f041 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -24,6 +24,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llcallbacklist.h" #include "lleventtimer.h" #include "llerrorlegacy.h" diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index 7a22eaf2032..33310c2e22c 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -33,7 +33,7 @@ #include "lltracethreadrecorder.h" #include "llcleanup.h" -#if LL_PROFILER_CONFIGURATION >= LL_PROFILER_CONFIG_TRACY && TRACY_ENABLE +#if LL_PROFILER_CONFIGURATION >= LL_PROFILER_CONFIG_TRACY && TRACY_ENABLE && !LL_LINUX // Override new/delete for tracy memory profiling void* ll_tracy_new(size_t size) @@ -54,7 +54,6 @@ void* ll_tracy_aligned_new(size_t size, size_t alignment) { throw std::bad_alloc(); } - LL_PROFILE_ALLOC(ptr, size); return ptr; } @@ -66,7 +65,6 @@ void ll_tracy_delete(void* ptr) void ll_tracy_aligned_delete(void* ptr) { - LL_PROFILE_FREE(ptr); ll_aligned_free_fallback(ptr); } diff --git a/indra/llcommon/lldeadmantimer.cpp b/indra/llcommon/lldeadmantimer.cpp index f9c14d7c24f..45c01eb84a7 100644 --- a/indra/llcommon/lldeadmantimer.cpp +++ b/indra/llcommon/lldeadmantimer.cpp @@ -25,6 +25,7 @@ * $/LicenseInfo$ */ +#include "linden_common.h" #include "lldeadmantimer.h" diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h index 232987da14f..0481e45351e 100644 --- a/indra/llcommon/lldefs.h +++ b/indra/llcommon/lldefs.h @@ -28,6 +28,7 @@ #define LL_LLDEFS_H #include "stdtypes.h" +#include #include // Often used array indices @@ -169,6 +170,38 @@ constexpr U32 MAXADDRSTR = 17; // 123.567.901.345 = 15 chars + \0 + // llclampb(a) // clamps a to [0 .. 255] // +// llless(d0, d1) safely compares d0 < d1 even if one is signed and the other +// is unsigned. A simple (d0 < d1) expression converts the signed operand to +// unsigned before comparing. If the signed operand is negative, that flips +// the negative value to a huge positive value, producing the wrong answer! +// llless() specifically addresses that case. +template +constexpr bool llless(T0 d0, T1 d1) +{ + if constexpr (std::is_signed_v && ! std::is_signed_v) + { + // T0 signed, T1 unsigned: negative d0 is less than any unsigned d1 + if (d0 < 0) + return true; + // both are non-negative: explicitly cast to avoid C4018 + return std::make_unsigned_t(d0) < d1; + } + else if constexpr (! std::is_signed_v && std::is_signed_v) + { + // T0 unsigned, T1 signed: any unsigned d0 is greater than negative d1 + if (d1 < 0) + return false; + // both are non-negative: explicitly cast to avoid C4018 + return d0 < std::make_unsigned_t(d1); + } + else + { + // both T0 and T1 are signed, or both are unsigned: + // straightforward comparison works + return d0 < d1; + } +} + // recursion tail template constexpr auto llmax(T data) @@ -180,7 +213,7 @@ template constexpr auto llmax(T0 d0, T1 d1, Ts... rest) { auto maxrest = llmax(d1, rest...); - return (d0 > maxrest)? d0 : maxrest; + return llless(maxrest, d0)? d0 : maxrest; } // recursion tail @@ -194,12 +227,28 @@ template constexpr auto llmin(T0 d0, T1 d1, Ts... rest) { auto minrest = llmin(d1, rest...); - return (d0 < minrest) ? d0 : minrest; + return llless(d0, minrest) ? d0 : minrest; } template constexpr A llclamp(A a, MIN minval, MAX maxval) { + // The only troublesome case is if A is unsigned and either minval or + // maxval is both signed and negative. Casting a negative number to + // unsigned flips it to a huge positive number, making this llclamp() call + // ineffective. + if constexpr (! std::is_signed_v) + { + if constexpr (std::is_signed_v) + { + assert(minval >= 0); + } + if constexpr (std::is_signed_v) + { + assert(maxval >= 0); + } + } + A aminval{ static_cast(minval) }, amaxval{ static_cast(maxval) }; if ( a < aminval ) { @@ -225,7 +274,7 @@ constexpr LLDATATYPE llclampb(LLDATATYPE a) } template -inline void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs) +constexpr void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs) { std::swap(lhs, rhs); } diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 41893a35e56..343cc47e4c3 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -91,13 +91,8 @@ const int LL_ERR_NOERR = 0; #define llverify(func) do {if (func) {}} while(0) #endif -#ifdef LL_WINDOWS #define LL_STATIC_ASSERT(func, msg) static_assert(func, msg) -#define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) static_assert(false, msg) -#else -#define LL_STATIC_ASSERT(func, msg) BOOST_STATIC_ASSERT(func) -#define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) BOOST_STATIC_ASSERT(sizeof(type) != 0 && false); -#endif +#define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) static_assert(sizeof(type) != 0 && false, msg) /** Error Logging Facility diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index 1c5fe9d2f53..c5a7a0e56b5 100644 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -387,6 +387,11 @@ void BlockTimer::logStats() } +#if defined(LL_GNUC) && GCC_VERSION >= 130000 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnonnull" +#endif + //static void BlockTimer::dumpCurTimes() { @@ -418,8 +423,12 @@ void BlockTimer::dumpCurTimes() << num_calls << " calls"; LL_INFOS() << out_str.str() << LL_ENDL; + } } -} + +#if defined(LL_GNUC) && GCC_VERSION >= 130000 +# pragma GCC diagnostic push +#endif //static void BlockTimer::writeLog(std::ostream& os) diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp index e36c1d0a4cf..abb0df0b87b 100644 --- a/indra/llcommon/llkeybind.cpp +++ b/indra/llcommon/llkeybind.cpp @@ -114,15 +114,6 @@ void LLKeyData::reset() mIgnoreMasks = false; } -LLKeyData& LLKeyData::operator=(const LLKeyData& rhs) -{ - mMouse = rhs.mMouse; - mKey = rhs.mKey; - mMask = rhs.mMask; - mIgnoreMasks = rhs.mIgnoreMasks; - return *this; -} - bool LLKeyData::operator==(const LLKeyData& rhs) { if (mMouse != rhs.mMouse) return false; diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h index 1bbb2fadb50..0a9d4600cca 100644 --- a/indra/llcommon/llkeybind.h +++ b/indra/llcommon/llkeybind.h @@ -43,7 +43,6 @@ class LL_COMMON_API LLKeyData bool isEmpty() const; bool empty() const { return isEmpty(); }; void reset(); - LLKeyData& operator=(const LLKeyData& rhs); bool operator==(const LLKeyData& rhs); bool operator!=(const LLKeyData& rhs); diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index b2a97345487..5269fb2282d 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -63,7 +63,17 @@ // Figure out differences between compilers -#if defined(__GNUC__) +#if defined(__clang__) + #define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + #ifndef LL_CLANG + #define LL_CLANG 1 + #endif + #ifndef LL_GNUC + #define LL_GNUC 1 + #endif +#elif defined(__GNUC__) #define GCC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index 912e596c3f3..2164fc1ad56 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -176,14 +176,14 @@ class WritePipeImpl: public LLProcess::WritePipe // In general, our streambuf might contain a number of different // physical buffers; iterate over those. bool keepwriting = true; - for (const_buffer_sequence::const_iterator bufi(bufs.begin()), bufend(bufs.end()); + for (auto bufi(boost::asio::buffer_sequence_begin(bufs)), bufend(boost::asio::buffer_sequence_end(bufs)); bufi != bufend && keepwriting; ++bufi) { // http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents // Although apr_file_write() accepts const void*, we // manipulate const char* so we can increment the pointer. - const char* remainptr = boost::asio::buffer_cast(*bufi); - std::size_t remainlen = boost::asio::buffer_size(*bufi); + const char* remainptr = static_cast(bufi->data()); + std::size_t remainlen = bufi->size(); while (remainlen) { // Tackle the current buffer in discrete chunks. On @@ -377,14 +377,14 @@ class ReadPipeImpl: public LLProcess::ReadPipe // In general, the mutable_buffer_sequence returned by prepare() might // contain a number of different physical buffers; iterate over those. std::size_t tocommit(0); - for (mutable_buffer_sequence::const_iterator bufi(bufs.begin()), bufend(bufs.end()); + for (auto bufi(boost::asio::buffer_sequence_begin(bufs)), bufend(boost::asio::buffer_sequence_end(bufs)); bufi != bufend; ++bufi) { // http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents - std::size_t toread(boost::asio::buffer_size(*bufi)); + std::size_t toread(bufi->size()); apr_size_t gotten(toread); apr_status_t err = apr_file_read(mPipe, - boost::asio::buffer_cast(*bufi), + bufi->data(), &gotten); // EAGAIN is exactly what we want from a nonblocking pipe. // Rather than waiting for data, it should return immediately. diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 718f4713213..9ca7ad46748 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -808,6 +808,20 @@ class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl }; #elif LL_LINUX + +// *NOTE:Mani - eww, macros! srry. +#define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \ + if (!cpuinfo[cpuinfo_id].empty()) \ + { setInfo(llpi_id, cpuinfo[cpuinfo_id]);} + +#define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \ + {\ + S32 result; \ + if (!cpuinfo[cpuinfo_id].empty() \ + && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \ + { setInfo(llpi_id, result);} \ + } + const char CPUINFO_FILE[] = "/proc/cpuinfo"; class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl @@ -819,8 +833,32 @@ class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl } virtual ~LLProcessorInfoLinuxImpl() {} + private: + F64 getCPUMaxMHZ() + { + // Nicky: We just look into cpu0. In theory we could iterate over all cores + // "/sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq" + // But those should not fluctuate that much? + std::ifstream fIn { "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq" }; + + if( !fIn.is_open() ) + return 0.0; + + std::string strLine; + fIn >> strLine; + if( strLine.empty() ) + return 0.0l; + + F64 mhz {}; + if( !LLStringUtil::convertToF64(strLine, mhz ) ) + return 0.0; + + mhz = mhz / 1000.0; + return mhz; + } + void get_proc_cpuinfo() { std::map< std::string, std::string > cpuinfo; @@ -855,24 +893,17 @@ class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl } # if LL_X86 -// *NOTE:Mani - eww, macros! srry. -#define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \ - if (!cpuinfo[cpuinfo_id].empty()) \ - { setInfo(llpi_id, cpuinfo[cpuinfo_id]);} - -#define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \ - {\ - S32 result; \ - if (!cpuinfo[cpuinfo_id].empty() \ - && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \ - { setInfo(llpi_id, result);} \ + F64 mhzFromSys = getCPUMaxMHZ(); + F64 mhzFromProc {}; + if( !LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhzFromProc ) ) + mhzFromProc = 0.0; + if (mhzFromSys > 1.0 && mhzFromSys > mhzFromProc ) + { + setInfo( eFrequency, mhzFromSys ); } - - F64 mhz; - if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) - && 200.0 < mhz && mhz < 10000.0) + else if ( 200.0 < mhzFromProc && mhzFromProc < 10000.0) { - setInfo(eFrequency,(F64)(mhz)); + setInfo(eFrequency,(F64)(mhzFromProc)); } LLPI_SET_INFO_STRING(eBrandName, "model name"); @@ -882,7 +913,7 @@ class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl LLPI_SET_INFO_INT(eModel, "model"); - S32 family; + S32 family{}; if (!cpuinfo["cpu family"].empty() && LLStringUtil::convertToS32(cpuinfo["cpu family"], family)) { diff --git a/indra/llcommon/llprocinfo.cpp b/indra/llcommon/llprocinfo.cpp index 69be00e14a0..9fe4af21031 100644 --- a/indra/llcommon/llprocinfo.cpp +++ b/indra/llcommon/llprocinfo.cpp @@ -25,6 +25,7 @@ * $/LicenseInfo$ */ +#include "linden_common.h" #include "llprocinfo.h" diff --git a/indra/llcommon/llprofiler.cpp b/indra/llcommon/llprofiler.cpp index bdddabf9776..b2ac7723d4f 100644 --- a/indra/llcommon/llprofiler.cpp +++ b/indra/llcommon/llprofiler.cpp @@ -25,6 +25,6 @@ * $/LicenseInfo$ */ -#include "linden_common.h" +#include "llpreprocessor.h" #include "TracyClient.cpp" diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h index 5fb32d62804..7c77d94475b 100644 --- a/indra/llcommon/llprofiler.h +++ b/indra/llcommon/llprofiler.h @@ -76,7 +76,16 @@ #if defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION > LL_PROFILER_CONFIG_NONE) #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER + #include "llpreprocessor.h" + +#if defined(LL_GNUC) && GCC_VERSION >= 130000 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnonnull" +#endif #include "tracy/Tracy.hpp" +#if defined(LL_GNUC) && GCC_VERSION >= 130000 +# pragma GCC diagnostic push +#endif // Enable RenderDoc labeling //#define LL_PROFILER_ENABLE_RENDER_DOC 0 diff --git a/indra/llcommon/llrand.cpp b/indra/llcommon/llrand.cpp index 2c51e6f07f9..513613f543c 100644 --- a/indra/llcommon/llrand.cpp +++ b/indra/llcommon/llrand.cpp @@ -58,9 +58,26 @@ * to restore uniform distribution. */ -// gRandomGenerator is a stateful static object, which is therefore not +// pRandomGenerator is a stateful static object, which is therefore not // inherently thread-safe. -static thread_local LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed()); +//We use a pointer to not construct a huge object in the TLS space, sadly this is necessary +// due to libcef.so on Linux being compiled with TLS model initial-exec (resulting in +// FLAG STATIC_TLS, see readelf libcef.so). CEFs own TLS objects + LLRandLagFib2281 then will exhaust the +// available TLS space, causing media failure. + +static thread_local std::unique_ptr< LLRandLagFib2281 > pRandomGenerator = nullptr; + +namespace { + F64 ll_internal_get_rand() + { + if( !pRandomGenerator ) + { + pRandomGenerator.reset(new LLRandLagFib2281(LLUUID::getRandomSeed( ) )); + } + + return(*pRandomGenerator)(); + } +} // no default implementation, only specific F64 and F32 specializations template @@ -73,7 +90,7 @@ inline F64 ll_internal_random() // CPUs (or at least multi-threaded processes) seem to // occasionally give an obviously incorrect random number -- like // 5^15 or something. Sooooo, clamp it as described above. - F64 rv{ gRandomGenerator() }; + F64 rv{ ll_internal_get_rand() }; if(!((rv >= 0.0) && (rv < 1.0))) return fmod(rv, 1.0); return rv; } @@ -85,7 +102,7 @@ inline F32 ll_internal_random() // Per Monty, it's important to clamp using the correct fmodf() rather // than expanding to F64 for fmod() and then truncating back to F32. Prior // to this change, we were getting sporadic ll_frand() == 1.0 results. - F32 rv{ narrow(gRandomGenerator()) }; + F32 rv{ narrow(ll_internal_get_rand()) }; if(!((rv >= 0.0f) && (rv < 1.0f))) return fmodf(rv, 1.0f); return rv; } diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 37af366a20b..c42eebebd18 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -2397,6 +2397,7 @@ U8* unzip_llsdNavMesh( bool& valid, size_t& outsize, std::istream& is, S32 size { case Z_NEED_DICT: ret = Z_DATA_ERROR; + [[fallthrough]]; case Z_DATA_ERROR: case Z_MEM_ERROR: inflateEnd(&strm); diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index dbd89118c9c..fd014841289 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -503,7 +503,7 @@ bool filter_llsd_with_template( * Helpers for llsd_matches() *****************************************************************************/ // raw data used for LLSD::Type lookup -struct Data +struct LLSDData { LLSD::Type type; const char* name; @@ -534,7 +534,7 @@ class TypeLookup { LL_PROFILE_ZONE_SCOPED; - for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di) + for (const LLSDData*di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di) { mMap[di->type] = di->name; } diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 21b11c53112..cfb16e18617 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -509,57 +509,46 @@ const S32 LLOSInfo::getOSBitness() const return mOSBitness; } -//static -U32 LLOSInfo::getProcessVirtualSizeKB() -{ - U32 virtual_size = 0; -#if LL_LINUX -# define STATUS_SIZE 2048 - LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); - if (status_filep) - { - S32 numRead = 0; - char buff[STATUS_SIZE]; /* Flawfinder: ignore */ +namespace { - size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); - buff[nbytes] = '\0'; + U32 readFromProcStat( std::string entryName ) + { + U32 val{}; +#if LL_LINUX + constexpr U32 STATUS_SIZE = 2048; - // All these guys return numbers in KB - char *memp = strstr(buff, "VmSize:"); - if (memp) + LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); + if (status_filep) { - numRead += sscanf(memp, "%*s %u", &virtual_size); + char buff[STATUS_SIZE]; /* Flawfinder: ignore */ + + size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); + buff[nbytes] = '\0'; + + // All these guys return numbers in KB + char *memp = strstr(buff, entryName.c_str()); + if (memp) + { + (void) sscanf(memp, "%*s %u", &val); + } + fclose(status_filep); } - fclose(status_filep); - } #endif - return virtual_size; + return val; + } + } //static -U32 LLOSInfo::getProcessResidentSizeKB() +U32 LLOSInfo::getProcessVirtualSizeKB() { - U32 resident_size = 0; -#if LL_LINUX - LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); - if (status_filep != NULL) - { - S32 numRead = 0; - char buff[STATUS_SIZE]; /* Flawfinder: ignore */ - - size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); - buff[nbytes] = '\0'; + return readFromProcStat( "VmSize:" ); +} - // All these guys return numbers in KB - char *memp = strstr(buff, "VmRSS:"); - if (memp) - { - numRead += sscanf(memp, "%*s %u", &resident_size); - } - fclose(status_filep); - } -#endif - return resident_size; +//static +U32 LLOSInfo::getProcessResidentSizeKB() +{ + return readFromProcStat( "VmRSS:" ); } //static @@ -724,7 +713,7 @@ class Stats void add(const LLSD::String& name, const T& value, typename boost::enable_if >::type* = 0) { - mStats[name] = LLSD::Integer(value); + mStats[name] = LLSD::Integer(llmin(value, S32_MAX)); } // Store every floating-point type as LLSD::Real. @@ -1083,7 +1072,7 @@ LLSD LLMemoryInfo::loadStatsMap() } #elif LL_LINUX - std::ifstream meminfo(MEMINFO_FILE); + llifstream meminfo(MEMINFO_FILE); if (meminfo.is_open()) { // MemTotal: 4108424 kB @@ -1123,9 +1112,10 @@ LLSD LLMemoryInfo::loadStatsMap() LLSD::String key(matched[1].first, matched[1].second); LLSD::String value_str(matched[2].first, matched[2].second); LLSD::Integer value(0); + S64 intval = 0; try { - value = boost::lexical_cast(value_str); + intval = llclamp(boost::lexical_cast(value_str), S32_MIN, S32_MAX); } catch (const boost::bad_lexical_cast&) { @@ -1134,6 +1124,7 @@ LLSD LLMemoryInfo::loadStatsMap() << line << LL_ENDL; continue; } + value = LLSD::Integer(intval); // Store this statistic. stats.add(key, value); } diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index c23adca7e86..f010f0e9615 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -32,11 +32,6 @@ #include "lltracethreadrecorder.h" #include "llthread.h" -inline F64 lerp(F64 a, F64 b, F64 u) -{ - return a + ((b - a) * u); -} - namespace LLTrace { @@ -302,7 +297,7 @@ F64 Recording::getMean( const StatType& stat ) { t = (F64)active_accumulator->getSampleCount() / (F64)div; } - return lerp(accumulator.getMean(), active_accumulator->getMean(), t); + return std::lerp(accumulator.getMean(), active_accumulator->getMean(), t); } else { @@ -388,7 +383,7 @@ F64 Recording::getMean( const StatType& stat ) { t = (F64)active_accumulator->getSampleCount() / (F64)div; } - return lerp(accumulator.getMean(), active_accumulator->getMean(), t); + return std::lerp(accumulator.getMean(), active_accumulator->getMean(), t); } else { diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index 3ec429530cd..e39c4029726 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -61,6 +61,8 @@ namespace { #ifdef __clang__ # pragma clang diagnostic ignored "-Wunused-function" +#elif defined(LL_GNUC) +# pragma GCC diagnostic ignored "-Wunused-function" #endif void test_that_error_h_includes_enough_things_to_compile_a_message() { diff --git a/indra/llfilesystem/lldiriterator.cpp b/indra/llfilesystem/lldiriterator.cpp index e8c37389d2a..b736a577bdf 100644 --- a/indra/llfilesystem/lldiriterator.cpp +++ b/indra/llfilesystem/lldiriterator.cpp @@ -24,6 +24,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "lldiriterator.h" #include "fix_macros.h" diff --git a/indra/llfilesystem/tests/lldir_test.cpp b/indra/llfilesystem/tests/lldir_test.cpp index d7d57fa86fb..4fa5769f652 100644 --- a/indra/llfilesystem/tests/lldir_test.cpp +++ b/indra/llfilesystem/tests/lldir_test.cpp @@ -27,12 +27,14 @@ #include "linden_common.h" +#include #include "llstring.h" #include "tests/StringVec.h" #include "../lldir.h" #include "../lldiriterator.h" #include "../test/lltut.h" +#include "../test/namedtempfile.h" #include "stringize.h" #include @@ -425,23 +427,19 @@ namespace tut return path; } - std::string makeTestDir( const std::string& dirbase ) + std::string makeTestDir( ) { - int counter; - std::string uniqueDir; - bool foundUnused; - std::string delim = gDirUtilp->getDirDelimiter(); + auto p = NamedTempFile::temp_path(); + std::filesystem::create_directories(p.native()); - for (counter=0, foundUnused=false; !foundUnused; counter++ ) - { - char counterStr[3]; - snprintf(counterStr, sizeof(counterStr), "%02d", counter); - uniqueDir = dirbase + counterStr; - foundUnused = ! ( LLFile::isdir(uniqueDir) || LLFile::isfile(uniqueDir) ); - } - ensure("test directory '" + uniqueDir + "' creation failed", !LLFile::mkdir(uniqueDir)); + std::string ret = p.string(); - return uniqueDir + delim; // HACK - apparently, the trailing delimiter is needed... + // There's an implicit assumtion all over this code that the returned path ends with "/" (or "\") + + if(ret.size() >= 1 && ret[ ret.size()-1 ] != std::filesystem::path::preferred_separator ) + ret += std::filesystem::path::preferred_separator; + + return ret; } static const char* DirScanFilename[5] = { "file1.abc", "file2.abc", "file1.xyz", "file2.xyz", "file1.mno" }; @@ -497,8 +495,9 @@ namespace tut // Create the same 5 file names of the two directories - std::string dir1 = makeTestDir(dirTemp + "LLDirIterator"); - std::string dir2 = makeTestDir(dirTemp + "LLDirIterator"); + std::string dir1 = makeTestDir(); + std::string dir2 = makeTestDir(); + std::string dir1files[5]; std::string dir2files[5]; for (int i=0; i<5; i++) diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp index d7a94d61a51..d37495f2a6d 100644 --- a/indra/llinventory/llsettingsbase.cpp +++ b/indra/llinventory/llsettingsbase.cpp @@ -25,6 +25,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llsettingsbase.h" #include "llmath.h" diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp index 2baf140e6a8..ebd8602c8dc 100644 --- a/indra/llinventory/llsettingsdaycycle.cpp +++ b/indra/llinventory/llsettingsdaycycle.cpp @@ -25,6 +25,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llsettingsdaycycle.h" #include "llerror.h" #include diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp index 4957cf3c02d..fd3e49041cf 100644 --- a/indra/llinventory/llsettingssky.cpp +++ b/indra/llinventory/llsettingssky.cpp @@ -25,6 +25,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llsettingssky.h" #include "indra_constants.h" #include diff --git a/indra/llinventory/llsettingswater.cpp b/indra/llinventory/llsettingswater.cpp index b5d59dc497c..427f06457f4 100644 --- a/indra/llinventory/llsettingswater.cpp +++ b/indra/llinventory/llsettingswater.cpp @@ -24,6 +24,7 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ +#include "linden_common.h" #include "llsettingswater.h" #include diff --git a/indra/llmath/llcalc.cpp b/indra/llmath/llcalc.cpp index e060b5df583..311e1e70599 100644 --- a/indra/llmath/llcalc.cpp +++ b/indra/llmath/llcalc.cpp @@ -116,17 +116,6 @@ void LLCalc::clearAllVariables() mVariables.clear(); } -/* -void LLCalc::updateVariables(LLSD& vars) -{ - LLSD::map_iterator cIt = vars.beginMap(); - for(; cIt != vars.endMap(); cIt++) - { - setVar(cIt->first, (F32)(LLSD::Real)cIt->second); - } -} -*/ - bool LLCalc::evalString(const std::string& expression, F32& result) { std::string expr_upper = expression; diff --git a/indra/llmath/llcalc.h b/indra/llmath/llcalc.h index 09672eb13b4..14797de996e 100644 --- a/indra/llmath/llcalc.h +++ b/indra/llmath/llcalc.h @@ -73,10 +73,9 @@ class LLCalc void setVar(const std::string& name, const F32& value); void clearVar(const std::string& name); void clearAllVariables(); -// void updateVariables(LLSD& vars); bool evalString(const std::string& expression, F32& result); - std::string::size_type getLastErrorPos() { return mLastErrorPos; } + std::string::size_type getLastErrorPos() const { return mLastErrorPos; } static LLCalc* getInstance(); static void cleanUp(); @@ -89,10 +88,6 @@ class LLCalc calc_map_t mConstants; calc_map_t mVariables; - // *TODO: Add support for storing user defined variables, and stored functions. - // Will need UI work, and a means to save them between sessions. -// calc_map_t mUserVariables; - // "There shall be only one" static LLCalc* sInstance; }; diff --git a/indra/llmath/llcalcparser.h b/indra/llmath/llcalcparser.h index ea71752ebca..fe4e6bb1a49 100644 --- a/indra/llmath/llcalcparser.h +++ b/indra/llmath/llcalcparser.h @@ -27,6 +27,13 @@ #ifndef LL_CALCPARSER_H #define LL_CALCPARSER_H +#include "llpreprocessor.h" + +#if defined(LL_GNUC) && GCC_VERSION >= 130000 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdangling-pointer" +#endif + #include #include #include @@ -35,6 +42,10 @@ #include using namespace boost::spirit::classic; +#if defined(LL_GNUC) && GCC_VERSION >= 130000 +# pragma GCC diagnostic pop +#endif + #include "llcalc.h" #include "llmath.h" @@ -131,14 +142,14 @@ struct LLCalcParser : grammar power = unary_expr[power.value = arg1] >> - *('^' >> assert_syntax(unary_expr[power.value = phoenix::bind(&powf)(power.value, arg1)])) + *('^' >> assert_syntax(unary_expr[power.value = phoenix::bind(&LLCalcParser::_pow)(self, power.value, arg1)])) ; term = power[term.value = arg1] >> *(('*' >> assert_syntax(power[term.value *= arg1])) | ('/' >> assert_syntax(power[term.value /= arg1])) | - ('%' >> assert_syntax(power[term.value = phoenix::bind(&fmodf)(term.value, arg1)])) + ('%' >> assert_syntax(power[term.value = phoenix::bind(&LLCalcParser::_fmod)(self, term.value, arg1)])) ) ; @@ -177,10 +188,11 @@ struct LLCalcParser : grammar F32 _floor(const F32& a) const { return (F32)llfloor(a); } F32 _ceil(const F32& a) const { return (F32)llceil(a); } F32 _atan2(const F32& a,const F32& b) const { return atan2(a,b); } + F32 _pow(const F32& a, const F32& b) const { return powf(a, b); } + F32 _fmod(const F32&a, const F32& b) const { return fmodf(a, b); } LLCalc::calc_map_t* mConstants; LLCalc::calc_map_t* mVariables; -// LLCalc::calc_map_t* mUserVariables; F32& mResult; }; diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index b3cb278d599..dfad66040ed 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2348,7 +2348,9 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) const LLSD::Binary& pos = mdl[i]["Position"].asBinary(); const LLSD::Binary& norm = mdl[i]["Normal"].asBinary(); +#if 0 // keep this code for now in case we decide to add support for on-the-wire tangents const LLSD::Binary& tangent = mdl[i]["Tangent"].asBinary(); +#endif const LLSD::Binary& tc = mdl[i]["TexCoord0"].asBinary(); const LLSD::Binary& idx = mdl[i]["TriangleList"].asBinary(); diff --git a/indra/llmessage/llavatarname.h b/indra/llmessage/llavatarname.h index eec966d51bf..86b2931ed9b 100644 --- a/indra/llmessage/llavatarname.h +++ b/indra/llmessage/llavatarname.h @@ -32,7 +32,7 @@ class LLSD; -class LL_COMMON_API LLAvatarName +class LLAvatarName { public: LLAvatarName(); diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 78cca47456e..9d940d8d711 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -23,6 +23,8 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llexperiencecache.h" #include "llavatarname.h" diff --git a/indra/llmessage/llstoredmessage.cpp b/indra/llmessage/llstoredmessage.cpp index 39696ea235e..ff8afde6576 100644 --- a/indra/llmessage/llstoredmessage.cpp +++ b/indra/llmessage/llstoredmessage.cpp @@ -24,6 +24,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llstoredmessage.h" LLStoredMessage::LLStoredMessage(const std::string& name, const LLSD& message) : mMessage(message), mName(name) diff --git a/indra/llmessage/lltemplatemessagedispatcher.cpp b/indra/llmessage/lltemplatemessagedispatcher.cpp index edbeb4acc15..02e5b56c8d5 100644 --- a/indra/llmessage/lltemplatemessagedispatcher.cpp +++ b/indra/llmessage/lltemplatemessagedispatcher.cpp @@ -24,6 +24,7 @@ * $/LicenseInfo$ */ +#include "linden_common.h" #include "lltemplatemessagedispatcher.h" diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 81ebe631c5a..71fc2b4fc08 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -1078,7 +1078,7 @@ bool LLDAELoader::OpenFile(const std::string& filename) LLModel* mdl = *i; if(mdl->getStatus() != LLModel::NO_ERRORS) { - setLoadState(ERROR_MODEL + mdl->getStatus()) ; + setLoadState(static_cast(ERROR_MODEL) + static_cast(mdl->getStatus())); return false; //abort } diff --git a/indra/llprimitive/llmaterialid.cpp b/indra/llprimitive/llmaterialid.cpp index 4992b282f36..b417f095ca5 100644 --- a/indra/llprimitive/llmaterialid.cpp +++ b/indra/llprimitive/llmaterialid.cpp @@ -56,20 +56,11 @@ LLMaterialID::LLMaterialID(const void* pMemory) set(pMemory); } -LLMaterialID::LLMaterialID(const LLMaterialID& pOtherMaterialID) -{ - copyFromOtherMaterialID(pOtherMaterialID); -} - LLMaterialID::LLMaterialID(const LLUUID& lluid) { set(lluid.mData); } -LLMaterialID::~LLMaterialID() -{ -} - bool LLMaterialID::operator == (const LLMaterialID& pOtherMaterialID) const { return (compareToOtherMaterialID(pOtherMaterialID) == 0); @@ -100,12 +91,6 @@ bool LLMaterialID::operator >= (const LLMaterialID& pOtherMaterialID) const return (compareToOtherMaterialID(pOtherMaterialID) >= 0); } -LLMaterialID& LLMaterialID::operator = (const LLMaterialID& pOtherMaterialID) -{ - copyFromOtherMaterialID(pOtherMaterialID); - return (*this); -} - bool LLMaterialID::isNull() const { return (compareToOtherMaterialID(LLMaterialID::null) == 0); @@ -168,18 +153,12 @@ std::ostream& operator<<(std::ostream& s, const LLMaterialID &material_id) return s; } - void LLMaterialID::parseFromBinary (const LLSD::Binary& pMaterialID) { llassert(pMaterialID.size() == (MATERIAL_ID_SIZE * sizeof(U8))); memcpy(mID, &pMaterialID[0], MATERIAL_ID_SIZE * sizeof(U8)); } -void LLMaterialID::copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID) -{ - memcpy(mID, pOtherMaterialID.get(), MATERIAL_ID_SIZE * sizeof(U8)); -} - int LLMaterialID::compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const { int retVal = 0; diff --git a/indra/llprimitive/llmaterialid.h b/indra/llprimitive/llmaterialid.h index bd6256d9619..cec09654412 100644 --- a/indra/llprimitive/llmaterialid.h +++ b/indra/llprimitive/llmaterialid.h @@ -39,9 +39,7 @@ class LLMaterialID LLMaterialID(const LLSD& pMaterialID); LLMaterialID(const LLSD::Binary& pMaterialID); LLMaterialID(const void* pMemory); - LLMaterialID(const LLMaterialID& pOtherMaterialID); LLMaterialID(const LLUUID& lluid); - ~LLMaterialID(); bool operator == (const LLMaterialID& pOtherMaterialID) const; bool operator != (const LLMaterialID& pOtherMaterialID) const; @@ -51,8 +49,6 @@ class LLMaterialID bool operator > (const LLMaterialID& pOtherMaterialID) const; bool operator >= (const LLMaterialID& pOtherMaterialID) const; - LLMaterialID& operator = (const LLMaterialID& pOtherMaterialID); - bool isNull() const; const U8* get() const; @@ -77,7 +73,6 @@ class LLMaterialID private: void parseFromBinary(const LLSD::Binary& pMaterialID); - void copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID); int compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const; U8 mID[MATERIAL_ID_SIZE]; diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp index 0383659f624..bce5f6adce7 100644 --- a/indra/llprimitive/llmodelloader.cpp +++ b/indra/llprimitive/llmodelloader.cpp @@ -24,6 +24,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llmodelloader.h" #include "llapp.h" diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp index 68f3f5ffacb..c70a8f6483f 100644 --- a/indra/llprimitive/llprimtexturelist.cpp +++ b/indra/llprimitive/llprimtexturelist.cpp @@ -137,7 +137,7 @@ S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te) // we're changing an existing entry llassert(mEntryList[index]); delete (mEntryList[index]); - if (&te) + if (te != LLTextureEntry::null) { mEntryList[index] = te.newCopy(); } diff --git a/indra/llprimitive/tests/llprimitive_test.cpp b/indra/llprimitive/tests/llprimitive_test.cpp index 0213a3e8b67..75c3613eceb 100644 --- a/indra/llprimitive/tests/llprimitive_test.cpp +++ b/indra/llprimitive/tests/llprimitive_test.cpp @@ -71,9 +71,7 @@ class DummyVolumeMgr : public LLVolumeMgr S32 mCurrDetailTest; }; -LLMaterialID::LLMaterialID() {} -LLMaterialID::LLMaterialID(LLMaterialID const &m) = default; -LLMaterialID::~LLMaterialID() {} +LLMaterialID::LLMaterialID() = default; void LLMaterialID::set(void const*) { } U8 const * LLMaterialID::get() const { return mID; } diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index ccff7c7a8c0..d0ae2d6b93b 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -23,7 +23,6 @@ set(llrender_SOURCE_FILES llglslshader.cpp llgltexture.cpp llimagegl.cpp - llpostprocess.cpp llrender.cpp llrender2dutils.cpp llrendernavprim.cpp @@ -56,7 +55,6 @@ set(llrender_HEADER_FILES llgltexture.h llgltypes.h llimagegl.h - llpostprocess.h llrender.h llrender2dutils.h llrendernavprim.h @@ -76,18 +74,17 @@ if (BUILD_HEADLESS) add_library (llrenderheadless ${llrender_SOURCE_FILES} ) - - set_property(TARGET llrenderheadless - PROPERTY COMPILE_DEFINITIONS LL_MESA=1 LL_MESA_HEADLESS=1 - ) + target_include_directories( llrenderheadless INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(llrenderheadless llcommon llimage llmath - llrender llxml llfilesystem + llwindowheadless + ll::freetype + OpenGL::GL ) endif (BUILD_HEADLESS) @@ -105,6 +102,5 @@ target_link_libraries(llrender llwindow ll::freetype OpenGL::GL - OpenGL::GLU ) diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index d13b98e2747..22d244d552e 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -215,8 +215,6 @@ LLMatrix4 gGLObliqueProjectionInverse; std::list LLGLUpdate::sGLQ; -#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS - #if LL_WINDOWS // WGL_ARB_create_context PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; @@ -236,8 +234,6 @@ PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC wglBlitContextFramebufferAMD = n PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr; PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = nullptr; -#endif - // GL_VERSION_1_2 //PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements = nullptr; //PFNGLTEXIMAGE3DPROC glTexImage3D = nullptr; @@ -1042,7 +1038,6 @@ void LLGLManager::initWGL() GLH_EXT_NAME(wglGetGPUIDsAMD) = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD"); GLH_EXT_NAME(wglGetGPUInfoAMD) = (PFNWGLGETGPUINFOAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUInfoAMD"); } - mHasNVXGpuMemoryInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts)) { @@ -1137,7 +1132,11 @@ bool LLGLManager::initGL() // Trailing space necessary to keep "nVidia Corpor_ati_on" cards // from being recognized as ATI. // NOTE: AMD has been pretty good about not breaking this check, do not rename without good reason - if (mGLVendor.substr(0,4) == "ATI ") + if (mGLVendor.substr(0,4) == "ATI " +#if LL_LINUX + || mGLVendor.find("AMD") != std::string::npos +#endif //LL_LINUX + ) { mGLVendorShort = "AMD"; // *TODO: Fix this? @@ -1203,16 +1202,29 @@ bool LLGLManager::initGL() { LL_WARNS("RenderInit") << "VRAM Detected (AMDAssociations):" << mVRAM << LL_ENDL; } - } - else if (mHasNVXGpuMemoryInfo) + } else +#endif +#if LL_WINDOWS || LL_LINUX { - GLint mem_kb = 0; - glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &mem_kb); - mVRAM = mem_kb / 1024; - - if (mVRAM != 0) + if (mHasNVXGpuMemoryInfo && mVRAM == 0) { - LL_WARNS("RenderInit") << "VRAM Detected (NVXGpuMemoryInfo):" << mVRAM << LL_ENDL; + GLint mem_kb = 0; + glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &mem_kb); + mVRAM = mem_kb / 1024; + + if (mVRAM != 0) + { + LL_WARNS("RenderInit") << "VRAM Detected (NVXGpuMemoryInfo):" << mVRAM << LL_ENDL; + } + } + + if (mHasATIMemInfo && mVRAM == 0) + { //ask the gl how much vram is free at startup and attempt to use no more than half of that + S32 meminfo[4]; + glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); + + mVRAM = meminfo[0] / 1024; + LL_INFOS("RenderInit") << "VRAM Detected (ATIMemInfo):" << mVRAM << LL_ENDL; } } #endif @@ -1378,6 +1390,9 @@ void LLGLManager::shutdownGL() void LLGLManager::initExtensions() { +#if LL_LINUX + glh_init_extensions(""); +#endif #if LL_DARWIN GLint num_extensions = 0; std::string all_extensions{""}; @@ -1406,6 +1421,16 @@ void LLGLManager::initExtensions() mHasAnisotropic = ExtensionExists("GL_EXT_texture_filter_anisotropic", gGLHExts.mSysExts); } +#if LL_WINDOWS || LL_LINUX + if( gGLHExts.mSysExts ) + { + mHasNVXGpuMemoryInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); + mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); + } + else + LL_WARNS() << "gGLHExts.mSysExts is not set.?" << LL_ENDL; +#endif + // Misc glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange); glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange); @@ -1413,10 +1438,9 @@ void LLGLManager::initExtensions() mInited = true; -#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS +#if LL_WINDOWS LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL; -#if LL_WINDOWS // WGL_AMD_gpu_association wglGetGPUIDsAMD = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD"); wglGetGPUInfoAMD = (PFNWGLGETGPUINFOAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUInfoAMD"); @@ -1434,8 +1458,6 @@ void LLGLManager::initExtensions() // WGL_ARB_create_context wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreateContextAttribsARB"); -#endif - // Load entire OpenGL API through GetProcAddress, leaving sections beyond mGLVersion unloaded @@ -2267,6 +2289,35 @@ void flush_glerror() glGetError(); } +const std::string getGLErrorString(GLenum error) +{ + switch(error) + { + case GL_NO_ERROR: + return "No Error"; + case GL_INVALID_ENUM: + return "Invalid Enum"; + case GL_INVALID_VALUE: + return "Invalid Value"; + case GL_INVALID_OPERATION: + return "Invalid Operation"; + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "Invalid Framebuffer Operation"; + case GL_OUT_OF_MEMORY: + return "Out of Memory"; + case GL_STACK_UNDERFLOW: + return "Stack Underflow"; + case GL_STACK_OVERFLOW: + return "Stack Overflow"; +#ifdef GL_TABLE_TOO_LARGE + case GL_TABLE_TOO_LARGE: + return "Table too large"; +#endif + default: + return "UNKNOWN ERROR"; + } +} + //this function outputs gl error to the log file, does not crash the code. void log_glerror() { @@ -2279,17 +2330,8 @@ void log_glerror() error = glGetError(); while (LL_UNLIKELY(error)) { - GLubyte const * gl_error_msg = gluErrorString(error); - if (NULL != gl_error_msg) - { - LL_WARNS() << "GL Error: " << error << " GL Error String: " << gl_error_msg << LL_ENDL ; - } - else - { - // gluErrorString returns NULL for some extensions' error codes. - // you'll probably have to grep for the number in glext.h. - LL_WARNS() << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << LL_ENDL; - } + std::string gl_error_msg = getGLErrorString(error); + LL_WARNS() << "GL Error: 0x" << std::hex << error << std::dec << " GL Error String: " << gl_error_msg << LL_ENDL; error = glGetError(); } } @@ -2303,27 +2345,12 @@ void do_assert_glerror() if (LL_UNLIKELY(error)) { quit = true; - GLubyte const * gl_error_msg = gluErrorString(error); - if (NULL != gl_error_msg) - { - LL_WARNS("RenderState") << "GL Error:" << error<< LL_ENDL; - LL_WARNS("RenderState") << "GL Error String:" << gl_error_msg << LL_ENDL; - - if (gDebugSession) - { - gFailLog << "GL Error:" << gl_error_msg << std::endl; - } - } - else + std::string gl_error_msg = getGLErrorString(error); + LL_WARNS("RenderState") << "GL Error: 0x" << std::hex << error << std::dec << LL_ENDL; + LL_WARNS("RenderState") << "GL Error String: " << gl_error_msg << LL_ENDL; + if (gDebugSession) { - // gluErrorString returns NULL for some extensions' error codes. - // you'll probably have to grep for the number in glext.h. - LL_WARNS("RenderState") << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << LL_ENDL; - - if (gDebugSession) - { - gFailLog << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << std::endl; - } + gFailLog << "GL Error: 0x" << std::hex << error << std::dec << " GL Error String: " << gl_error_msg << std::endl; } } @@ -2566,6 +2593,7 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor { return; } + LL_INFOS() << "GL: " << version << LL_ENDL; version_string->assign(version); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 24ba4d6deb4..8a00e513aea 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -99,6 +99,7 @@ class LLGLManager // Vendor-specific extensions bool mHasAMDAssociations = false; bool mHasNVXGpuMemoryInfo = false; + bool mHasATIMemInfo = false; bool mIsAMD; bool mIsNVIDIA; diff --git a/indra/llrender/llglcommonfunc.cpp b/indra/llrender/llglcommonfunc.cpp index 13b08de7cc1..bf4d337b503 100644 --- a/indra/llrender/llglcommonfunc.cpp +++ b/indra/llrender/llglcommonfunc.cpp @@ -24,6 +24,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llglheaders.h" #include "llglcommonfunc.h" diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 3d4dc5e6982..ad31921c05d 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -41,6 +41,22 @@ # include "GL/glh_extensions.h" # undef __APPLE__ +#elif LL_LINUX +#define GL_GLEXT_PROTOTYPES +#define GLX_GLEXT_PROTOTYPES + +#include "GL/gl.h" +#include "GL/glext.h" + +// The __APPLE__ kludge is to make glh_extensions.h not symbol-clash horribly +# define __APPLE__ +# include "GL/glh_extensions.h" +# undef __APPLE__ + +# include "GL/glx.h" +# include "GL/glxext.h" + + #elif LL_WINDOWS //---------------------------------------------------------------------------- // LL_WINDOWS diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 97ea6f67bd8..e3198163779 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1053,7 +1053,11 @@ U32 type_width_from_pixtype(U32 pixtype) bool should_stagger_image_set(bool compressed) { -#if LL_DARWIN +#if LL_MESA_HEADLESS + return false; +#elif LL_LINUX + return !compressed && on_main_thread() && gGLManager.mIsNVIDIA; +#elif LL_DARWIN return !compressed && on_main_thread() && gGLManager.mIsAMD; #else // glTexSubImage2D doesn't work with compressed textures on select tested Nvidia GPUs on Windows 10 -Cosmic,2023-03-08 diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp deleted file mode 100644 index eef7193c92b..00000000000 --- a/indra/llrender/llpostprocess.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/** - * @file llpostprocess.cpp - * @brief LLPostProcess class implementation - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llpostprocess.h" -#include "llglslshader.h" -#include "llsdserialize.h" -#include "llrender.h" - -static LLStaticHashedString sRenderTexture("RenderTexture"); -static LLStaticHashedString sBrightness("brightness"); -static LLStaticHashedString sContrast("contrast"); -static LLStaticHashedString sContrastBase("contrastBase"); -static LLStaticHashedString sSaturation("saturation"); -static LLStaticHashedString sLumWeights("lumWeights"); -static LLStaticHashedString sNoiseTexture("NoiseTexture"); -static LLStaticHashedString sBrightMult("brightMult"); -static LLStaticHashedString sNoiseStrength("noiseStrength"); -static LLStaticHashedString sExtractLow("extractLow"); -static LLStaticHashedString sExtractHigh("extractHigh"); -static LLStaticHashedString sBloomStrength("bloomStrength"); -static LLStaticHashedString sTexelSize("texelSize"); -static LLStaticHashedString sBlurDirection("blurDirection"); -static LLStaticHashedString sBlurWidth("blurWidth"); - -LLPostProcess * gPostProcess = NULL; - -static const unsigned int NOISE_SIZE = 512; - -LLPostProcess::LLPostProcess(void) : - initialized(false), - mAllEffects(LLSD::emptyMap()), - screenW(1), screenH(1) -{ - mSceneRenderTexture = NULL ; - mNoiseTexture = NULL ; - mTempBloomTexture = NULL ; - - noiseTextureScale = 1.0f; - - /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender. - std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); - LL_DEBUGS("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL; - - llifstream effectsXML(pathName); - - if (effectsXML) - { - LLPointer parser = new LLSDXMLParser(); - - parser->parse(effectsXML, mAllEffects, LLSDSerialize::SIZE_UNLIMITED); - } - - if (!mAllEffects.has("default")) - { - LLSD & defaultEffect = (mAllEffects["default"] = LLSD::emptyMap()); - - defaultEffect["enable_night_vision"] = LLSD::Boolean(false); - defaultEffect["enable_bloom"] = LLSD::Boolean(false); - defaultEffect["enable_color_filter"] = LLSD::Boolean(false); - - /// NVG Defaults - defaultEffect["brightness_multiplier"] = 3.0; - defaultEffect["noise_size"] = 25.0; - defaultEffect["noise_strength"] = 0.4; - - // TODO BTest potentially add this to tweaks? - noiseTextureScale = 1.0f; - - /// Bloom Defaults - defaultEffect["extract_low"] = 0.95; - defaultEffect["extract_high"] = 1.0; - defaultEffect["bloom_width"] = 2.25; - defaultEffect["bloom_strength"] = 1.5; - - /// Color Filter Defaults - defaultEffect["brightness"] = 1.0; - defaultEffect["contrast"] = 1.0; - defaultEffect["saturation"] = 1.0; - - LLSD& contrastBase = (defaultEffect["contrast_base"] = LLSD::emptyArray()); - contrastBase.append(1.0); - contrastBase.append(1.0); - contrastBase.append(1.0); - contrastBase.append(0.5); - } - - setSelectedEffect("default"); - */ -} - -LLPostProcess::~LLPostProcess(void) -{ - invalidate() ; -} - -// static -void LLPostProcess::initClass(void) -{ - //this will cause system to crash at second time login - //if first time login fails due to network connection --- bao - //***llassert_always(gPostProcess == NULL); - //replaced by the following line: - if(gPostProcess) - return ; - - - gPostProcess = new LLPostProcess(); -} - -// static -void LLPostProcess::cleanupClass() -{ - delete gPostProcess; - gPostProcess = NULL; -} - -void LLPostProcess::setSelectedEffect(std::string const & effectName) -{ - mSelectedEffectName = effectName; - static_cast(tweaks) = mAllEffects[effectName]; -} - -void LLPostProcess::saveEffect(std::string const & effectName) -{ - /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender. - mAllEffects[effectName] = tweaks; - - std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); - //LL_INFOS() << "Saving PostProcess Effects settings to " << pathName << LL_ENDL; - - llofstream effectsXML(pathName); - - LLPointer formatter = new LLSDXMLFormatter(); - - formatter->format(mAllEffects, effectsXML); - */ -} -void LLPostProcess::invalidate() -{ - mSceneRenderTexture = NULL ; - mNoiseTexture = NULL ; - mTempBloomTexture = NULL ; - initialized = false ; -} - -void LLPostProcess::apply(unsigned int width, unsigned int height) -{ - if (!initialized || width != screenW || height != screenH){ - initialize(width, height); - } - if (shadersEnabled()){ - doEffects(); - } -} - -void LLPostProcess::initialize(unsigned int width, unsigned int height) -{ - screenW = width; - screenH = height; - createTexture(mSceneRenderTexture, screenW, screenH); - initialized = true; - - checkError(); - createNightVisionShader(); - createBloomShader(); - createColorFilterShader(); - checkError(); -} - -inline bool LLPostProcess::shadersEnabled(void) -{ - return (tweaks.useColorFilter().asBoolean() || - tweaks.useNightVisionShader().asBoolean() || - tweaks.useBloomShader().asBoolean() ); - -} - -void LLPostProcess::applyShaders(void) -{ - if (tweaks.useColorFilter()){ - applyColorFilterShader(); - checkError(); - } - if (tweaks.useNightVisionShader()){ - /// If any of the above shaders have been called update the frame buffer; - if (tweaks.useColorFilter()) - { - U32 tex = mSceneRenderTexture->getTexName() ; - copyFrameBuffer(tex, screenW, screenH); - } - applyNightVisionShader(); - checkError(); - } - if (tweaks.useBloomShader()){ - /// If any of the above shaders have been called update the frame buffer; - if (tweaks.useColorFilter().asBoolean() || tweaks.useNightVisionShader().asBoolean()) - { - U32 tex = mSceneRenderTexture->getTexName() ; - copyFrameBuffer(tex, screenW, screenH); - } - applyBloomShader(); - checkError(); - } -} - -void LLPostProcess::applyColorFilterShader(void) -{ - -} - -void LLPostProcess::createColorFilterShader(void) -{ - /// Define uniform names - colorFilterUniforms[sRenderTexture] = 0; - colorFilterUniforms[sBrightness] = 0; - colorFilterUniforms[sContrast] = 0; - colorFilterUniforms[sContrastBase] = 0; - colorFilterUniforms[sSaturation] = 0; - colorFilterUniforms[sLumWeights] = 0; -} - -void LLPostProcess::applyNightVisionShader(void) -{ - -} - -void LLPostProcess::createNightVisionShader(void) -{ - /// Define uniform names - nightVisionUniforms[sRenderTexture] = 0; - nightVisionUniforms[sNoiseTexture] = 0; - nightVisionUniforms[sBrightMult] = 0; - nightVisionUniforms[sNoiseStrength] = 0; - nightVisionUniforms[sLumWeights] = 0; - - createNoiseTexture(mNoiseTexture); -} - -void LLPostProcess::applyBloomShader(void) -{ - -} - -void LLPostProcess::createBloomShader(void) -{ - createTexture(mTempBloomTexture, unsigned(screenW * 0.5), unsigned(screenH * 0.5)); - - /// Create Bloom Extract Shader - bloomExtractUniforms[sRenderTexture] = 0; - bloomExtractUniforms[sExtractLow] = 0; - bloomExtractUniforms[sExtractHigh] = 0; - bloomExtractUniforms[sLumWeights] = 0; - - /// Create Bloom Blur Shader - bloomBlurUniforms[sRenderTexture] = 0; - bloomBlurUniforms[sBloomStrength] = 0; - bloomBlurUniforms[sTexelSize] = 0; - bloomBlurUniforms[sBlurDirection] = 0; - bloomBlurUniforms[sBlurWidth] = 0; -} - -void LLPostProcess::getShaderUniforms(glslUniforms & uniforms, GLuint & prog) -{ - /// Find uniform locations and insert into map - glslUniforms::iterator i; - for (i = uniforms.begin(); i != uniforms.end(); ++i){ - i->second = glGetUniformLocation(prog, i->first.String().c_str()); - } -} - -void LLPostProcess::doEffects(void) -{ - /// Save GL State - glPushAttrib(GL_ALL_ATTRIB_BITS); - glPushClientAttrib(GL_ALL_ATTRIB_BITS); - - /// Copy the screen buffer to the render texture - { - U32 tex = mSceneRenderTexture->getTexName() ; - copyFrameBuffer(tex, screenW, screenH); - } - - /// Clear the frame buffer. - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - /// Change to an orthogonal view - viewOrthogonal(screenW, screenH); - - checkError(); - applyShaders(); - - LLGLSLShader::unbind(); - checkError(); - - /// Change to a perspective view - viewPerspective(); - - /// Reset GL State - glPopClientAttrib(); - glPopAttrib(); - checkError(); -} - -void LLPostProcess::copyFrameBuffer(U32 & texture, unsigned int width, unsigned int height) -{ - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture); - glCopyTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, 0, 0, width, height, 0); -} - -void LLPostProcess::drawOrthoQuad(unsigned int width, unsigned int height, QuadType type) -{ - -} - -void LLPostProcess::viewOrthogonal(unsigned int width, unsigned int height) -{ - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.ortho( 0.f, (GLfloat) width , (GLfloat) height , 0.f, -1.f, 1.f ); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - gGL.loadIdentity(); -} - -void LLPostProcess::viewPerspective(void) -{ - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); -} - -void LLPostProcess::changeOrthogonal(unsigned int width, unsigned int height) -{ - viewPerspective(); - viewOrthogonal(width, height); -} - -void LLPostProcess::createTexture(LLPointer& texture, unsigned int width, unsigned int height) -{ - std::vector data(width * height * 4, 0) ; - - texture = new LLImageGL(false) ; - if(texture->createGLTexture()) - { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture->getTexName()); - glTexImage2D(GL_TEXTURE_RECTANGLE, 0, 4, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - } -} - -void LLPostProcess::createNoiseTexture(LLPointer& texture) -{ - std::vector buffer(NOISE_SIZE * NOISE_SIZE); - for (unsigned int i = 0; i < NOISE_SIZE; i++){ - for (unsigned int k = 0; k < NOISE_SIZE; k++){ - buffer[(i * NOISE_SIZE) + k] = (GLubyte)((double) rand() / ((double) RAND_MAX + 1.f) * 255.f); - } - } - - texture = new LLImageGL(false) ; - if(texture->createGLTexture()) - { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture->getTexName()); - LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); - } -} - -bool LLPostProcess::checkError(void) -{ - GLenum glErr; - bool retCode = false; - - glErr = glGetError(); - while (glErr != GL_NO_ERROR) - { - // shaderErrorLog << (const char *) gluErrorString(glErr) << std::endl; - char const * err_str_raw = (const char *) gluErrorString(glErr); - - if(err_str_raw == NULL) - { - std::ostringstream err_builder; - err_builder << "unknown error number " << glErr; - mShaderErrorString = err_builder.str(); - } - else - { - mShaderErrorString = err_str_raw; - } - - retCode = true; - glErr = glGetError(); - } - return retCode; -} - -void LLPostProcess::checkShaderError(GLuint shader) -{ - GLint infologLength = 0; - GLint charsWritten = 0; - GLchar *infoLog; - - checkError(); // Check for OpenGL errors - - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength); - - checkError(); // Check for OpenGL errors - - if (infologLength > 0) - { - infoLog = (GLchar *)malloc(infologLength); - if (infoLog == NULL) - { - /// Could not allocate infolog buffer - return; - } - glGetProgramInfoLog(shader, infologLength, &charsWritten, infoLog); - // shaderErrorLog << (char *) infoLog << std::endl; - mShaderErrorString = (char *) infoLog; - free(infoLog); - } - checkError(); // Check for OpenGL errors -} diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h deleted file mode 100644 index b5b7549efb3..00000000000 --- a/indra/llrender/llpostprocess.h +++ /dev/null @@ -1,267 +0,0 @@ -/** - * @file llpostprocess.h - * @brief LLPostProcess class definition - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_POSTPROCESS_H -#define LL_POSTPROCESS_H - -#include -#include -#include "llgl.h" -#include "llglheaders.h" -#include "llstaticstringtable.h" - -class LLPostProcess -{ -public: - - typedef enum _QuadType { - QUAD_NORMAL, - QUAD_NOISE, - QUAD_BLOOM_EXTRACT, - QUAD_BLOOM_COMBINE - } QuadType; - - /// GLSL Shader Encapsulation Struct - typedef LLStaticStringTable glslUniforms; - - struct PostProcessTweaks : public LLSD { - inline PostProcessTweaks() : LLSD(LLSD::emptyMap()) - { - } - - inline LLSD & brightMult() { - return (*this)["brightness_multiplier"]; - } - - inline LLSD & noiseStrength() { - return (*this)["noise_strength"]; - } - - inline LLSD & noiseSize() { - return (*this)["noise_size"]; - } - - inline LLSD & extractLow() { - return (*this)["extract_low"]; - } - - inline LLSD & extractHigh() { - return (*this)["extract_high"]; - } - - inline LLSD & bloomWidth() { - return (*this)["bloom_width"]; - } - - inline LLSD & bloomStrength() { - return (*this)["bloom_strength"]; - } - - inline LLSD & brightness() { - return (*this)["brightness"]; - } - - inline LLSD & contrast() { - return (*this)["contrast"]; - } - - inline LLSD & contrastBaseR() { - return (*this)["contrast_base"][0]; - } - - inline LLSD & contrastBaseG() { - return (*this)["contrast_base"][1]; - } - - inline LLSD & contrastBaseB() { - return (*this)["contrast_base"][2]; - } - - inline LLSD & contrastBaseIntensity() { - return (*this)["contrast_base"][3]; - } - - inline LLSD & saturation() { - return (*this)["saturation"]; - } - - inline LLSD & useNightVisionShader() { - return (*this)["enable_night_vision"]; - } - - inline LLSD & useBloomShader() { - return (*this)["enable_bloom"]; - } - - inline LLSD & useColorFilter() { - return (*this)["enable_color_filter"]; - } - - - inline F32 getBrightMult() const { - return F32((*this)["brightness_multiplier"].asReal()); - } - - inline F32 getNoiseStrength() const { - return F32((*this)["noise_strength"].asReal()); - } - - inline F32 getNoiseSize() const { - return F32((*this)["noise_size"].asReal()); - } - - inline F32 getExtractLow() const { - return F32((*this)["extract_low"].asReal()); - } - - inline F32 getExtractHigh() const { - return F32((*this)["extract_high"].asReal()); - } - - inline F32 getBloomWidth() const { - return F32((*this)["bloom_width"].asReal()); - } - - inline F32 getBloomStrength() const { - return F32((*this)["bloom_strength"].asReal()); - } - - inline F32 getBrightness() const { - return F32((*this)["brightness"].asReal()); - } - - inline F32 getContrast() const { - return F32((*this)["contrast"].asReal()); - } - - inline F32 getContrastBaseR() const { - return F32((*this)["contrast_base"][0].asReal()); - } - - inline F32 getContrastBaseG() const { - return F32((*this)["contrast_base"][1].asReal()); - } - - inline F32 getContrastBaseB() const { - return F32((*this)["contrast_base"][2].asReal()); - } - - inline F32 getContrastBaseIntensity() const { - return F32((*this)["contrast_base"][3].asReal()); - } - - inline F32 getSaturation() const { - return F32((*this)["saturation"].asReal()); - } - - }; - - bool initialized; - PostProcessTweaks tweaks; - - // the map of all availible effects - LLSD mAllEffects; - -private: - LLPointer mSceneRenderTexture ; - LLPointer mNoiseTexture ; - LLPointer mTempBloomTexture ; - -public: - LLPostProcess(void); - - ~LLPostProcess(void); - - void apply(unsigned int width, unsigned int height); - void invalidate() ; - - /// Perform global initialization for this class. - static void initClass(void); - - // Cleanup of global data that's only inited once per class. - static void cleanupClass(); - - void setSelectedEffect(std::string const & effectName); - - inline std::string const & getSelectedEffect(void) const { - return mSelectedEffectName; - } - - void saveEffect(std::string const & effectName); - -private: - /// read in from file - std::string mShaderErrorString; - unsigned int screenW; - unsigned int screenH; - - float noiseTextureScale; - - /// Shader Uniforms - glslUniforms nightVisionUniforms; - glslUniforms bloomExtractUniforms; - glslUniforms bloomBlurUniforms; - glslUniforms colorFilterUniforms; - - // the name of currently selected effect in mAllEffects - // invariant: tweaks == mAllEffects[mSelectedEffectName] - std::string mSelectedEffectName; - - /// General functions - void initialize(unsigned int width, unsigned int height); - void doEffects(void); - void applyShaders(void); - bool shadersEnabled(void); - - /// Night Vision Functions - void createNightVisionShader(void); - void applyNightVisionShader(void); - - /// Bloom Functions - void createBloomShader(void); - void applyBloomShader(void); - - /// Color Filter Functions - void createColorFilterShader(void); - void applyColorFilterShader(void); - - /// OpenGL Helper Functions - void getShaderUniforms(glslUniforms & uniforms, GLuint & prog); - void createTexture(LLPointer& texture, unsigned int width, unsigned int height); - void copyFrameBuffer(U32 & texture, unsigned int width, unsigned int height); - void createNoiseTexture(LLPointer& texture); - bool checkError(void); - void checkShaderError(GLuint shader); - void drawOrthoQuad(unsigned int width, unsigned int height, QuadType type); - void viewOrthogonal(unsigned int width, unsigned int height); - void changeOrthogonal(unsigned int width, unsigned int height); - void viewPerspective(void); -}; - -extern LLPostProcess * gPostProcess; - - -#endif // LL_POSTPROCESS_H diff --git a/indra/llrender/lltexturemanagerbridge.cpp b/indra/llrender/lltexturemanagerbridge.cpp index c243f0697ae..67838418bfc 100644 --- a/indra/llrender/lltexturemanagerbridge.cpp +++ b/indra/llrender/lltexturemanagerbridge.cpp @@ -24,6 +24,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "lltexturemanagerbridge.h" // Define a null texture manager bridge. Applications must provide their own bridge implementaton. diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 08b3df87abe..fe45df40219 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -12,12 +12,14 @@ project(llwindow) include(00-Common) include(DragDrop) +include(Linking) include(LLCommon) include(LLImage) include(LLWindow) include(UI) include(ViewerMiscLibs) include(GLM) +include(SDL3) set(llwindow_SOURCE_FILES llcursortypes.cpp @@ -58,34 +60,24 @@ set(llwindow_LINK_LIBRARIES ll::glm ll::glext ll::uilibraries - ll::SDL ) -# Libraries on which this library depends, needed for Linux builds -# Sort by high-level to low-level -if (LINUX) + +if (USE_SDL_WINDOW) list(APPEND viewer_SOURCE_FILES + llsdl.cpp llkeyboardsdl.cpp llwindowsdl.cpp ) list(APPEND viewer_HEADER_FILES + llsdl.h llkeyboardsdl.h llwindowsdl.h ) - if (BUILD_HEADLESS) - set(llwindowheadless_LINK_LIBRARIES - ${LLCOMMON_LIBRARIES} - ${LLIMAGE_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLRENDER_HEADLESS_LIBRARIES} - ${LLFILESYSTEM_LIBRARIES} - ${LLWINDOW_HEADLESS_LIBRARIES} - ${LLXML_LIBRARIES} - fontconfig # For FCInit and other FC* functions. - ) - endif (BUILD_HEADLESS) - -endif (LINUX) + list(APPEND llwindow_LINK_LIBRARIES + ll::SDL3 + ) +endif () if (DARWIN) list(APPEND llwindow_SOURCE_FILES @@ -133,32 +125,51 @@ if (WINDOWS) ) endif (WINDOWS) -if (SOLARIS) - list(APPEND llwindow_SOURCE_FILES - llwindowsolaris.cpp - ) - list(APPEND llwindow_HEADER_FILES - llwindowsolaris.h - ) -endif (SOLARIS) if (BUILD_HEADLESS) set(llwindowheadless_SOURCE_FILES - llwindowmesaheadless.cpp - llmousehandler.cpp - ) + llcursortypes.cpp + llkeyboard.cpp + llkeyboardheadless.cpp + llwindowheadless.cpp + llwindowcallbacks.cpp + llwindow.cpp + llwindowmesaheadless.cpp + llmousehandler.cpp + ) + set(llwindowheadless_HEADER_FILES - llwindowmesaheadless.h - llmousehandler.h - ) + llcursortypes.h + llkeyboard.h + llkeyboardheadless.h + llwindowheadless.h + llwindowcallbacks.h + llwindowmesaheadless.h + llmousehandler.h + ) + add_library (llwindowheadless - ${llwindow_SOURCE_FILES} ${llwindowheadless_SOURCE_FILES} + ${llwindowheadless_HEADER_FILES} ) - set_property(TARGET llwindowheadless - PROPERTY COMPILE_DEFINITIONS LL_MESA=1 LL_MESA_HEADLESS=1 - ) - target_link_libraries (llwindowheadless ${llwindowheadless_LINK_LIBRARIES} dl) + + target_compile_definitions( llwindowheadless PUBLIC LL_MESA=1 LL_MESA_HEADLESS=1 ) + + target_link_libraries (llwindowheadless + llcommon + llimage + llmath + llrenderheadless + llfilesystem + llxml + ll::glm + ll::glext + ll::zlib-ng + PkgConfig::OSMESA + fontconfig + dl + ) + target_include_directories(llwindowheadless INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) endif (BUILD_HEADLESS) if (llwindow_HEADER_FILES) @@ -172,14 +183,12 @@ endif (llwindow_HEADER_FILES) ${viewer_SOURCE_FILES} ) -if (SDL_FOUND) - set_property(TARGET llwindow - PROPERTY COMPILE_DEFINITIONS LL_SDL=1 - ) -endif (SDL_FOUND) +target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES}) +target_include_directories(llwindow INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES}) - target_include_directories(llwindow INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +if (USE_SDL_WINDOW) + target_compile_definitions( llwindow PUBLIC LL_SDL_WINDOW=1 ) +endif() if (DARWIN) target_link_libraries(llwindow ${CARBON_LIBRARY}) diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index 33eebdadd15..761b4a18709 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -41,7 +41,6 @@ std::map LLKeyboard::sKeysToNames; std::map LLKeyboard::sNamesToKeys; LLKeyStringTranslatorFunc* LLKeyboard::mStringTranslator = NULL; // Used for l10n + PC/Mac/Linux accelerator labeling - // // Class Implementation // @@ -162,6 +161,7 @@ void LLKeyboard::resetKeyDownAndHandle() mCallbacks->handleTranslatedKeyUp(i, mask); } } + mCurTranslatedKey = KEY_NONE; } // BUG this has to be called when an OS dialog is shown, otherwise modifier key state @@ -195,12 +195,10 @@ void LLKeyboard::resetKeys() } -bool LLKeyboard::translateKey(const U16 os_key, KEY *out_key) +bool LLKeyboard::translateKey(const NATIVE_KEY_TYPE os_key, KEY *out_key) { - std::map::iterator iter; - // Only translate keys in the map, ignore all other keys for now - iter = mTranslateKeyMap.find(os_key); + auto iter = mTranslateKeyMap.find(os_key); if (iter == mTranslateKeyMap.end()) { //LL_WARNS() << "Unknown virtual key " << os_key << LL_ENDL; @@ -214,11 +212,9 @@ bool LLKeyboard::translateKey(const U16 os_key, KEY *out_key) } } - -U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) +LLKeyboard::NATIVE_KEY_TYPE LLKeyboard::inverseTranslateKey(const KEY translated_key) { - std::map::iterator iter; - iter = mInvTranslateKeyMap.find(translated_key); + auto iter = mInvTranslateKeyMap.find(translated_key); if (iter == mInvTranslateKeyMap.end()) { return 0; @@ -230,7 +226,7 @@ U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) } -bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask) +bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key, MASK translated_mask) { bool handled = false; bool repeated = false; @@ -258,7 +254,7 @@ bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask } -bool LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask) +bool LLKeyboard::handleTranslatedKeyUp(KEY translated_key, MASK translated_mask) { bool handled = false; if( mKeyLevel[translated_key] ) diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index 713eb7aec24..b4ab562cd56 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -55,6 +55,13 @@ class LLWindowCallbacks; class LLKeyboard { public: +#ifdef LL_SDL_WINDOW + // linux relies on SDL2 which uses U32 for its native key type + typedef U32 NATIVE_KEY_TYPE; +#else + // on non-linux platforms we can get by with a smaller native key type + typedef U16 NATIVE_KEY_TYPE; +#endif LLKeyboard(); virtual ~LLKeyboard(); @@ -67,16 +74,15 @@ class LLKeyboard bool getKeyDown(const KEY key) { return mKeyLevel[key]; } bool getKeyRepeated(const KEY key) { return mKeyRepeated[key]; } - bool translateKey(const U16 os_key, KEY *translated_key); - U16 inverseTranslateKey(const KEY translated_key); - bool handleTranslatedKeyUp(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes - bool handleTranslatedKeyDown(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes - + bool translateKey(const NATIVE_KEY_TYPE os_key, KEY *translated_key); + NATIVE_KEY_TYPE inverseTranslateKey(const KEY translated_key); + bool handleTranslatedKeyUp(KEY translated_key, MASK translated_mask); // Translated into "Linden" keycodes + bool handleTranslatedKeyDown(KEY translated_key, MASK translated_mask); // Translated into "Linden" keycodes - virtual bool handleKeyUp(const U16 key, MASK mask) = 0; - virtual bool handleKeyDown(const U16 key, MASK mask) = 0; + virtual bool handleKeyUp(const NATIVE_KEY_TYPE key, MASK mask) = 0; + virtual bool handleKeyDown(const NATIVE_KEY_TYPE key, MASK mask) = 0; -#ifdef LL_DARWIN +#if LL_DARWIN && !LL_SDL_WINDOW // We only actually use this for macOS. virtual void handleModifier(MASK mask) = 0; #endif // LL_DARWIN @@ -111,8 +117,8 @@ class LLKeyboard void addKeyName(KEY key, const std::string& name); protected: - std::map mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs - std::map mInvTranslateKeyMap; // Map of translations from Linden KEYs to OS keys + std::map mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs + std::map mInvTranslateKeyMap; // Map of translations from Linden KEYs to OS keys LLWindowCallbacks *mCallbacks; LLTimer mKeyLevelTimer[KEY_COUNT]; // Time since level was set diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp index 8669a5b41ad..50d03aaf203 100644 --- a/indra/llwindow/llkeyboardheadless.cpp +++ b/indra/llwindow/llkeyboardheadless.cpp @@ -31,21 +31,23 @@ LLKeyboardHeadless::LLKeyboardHeadless() { } -void LLKeyboardHeadless::resetMaskKeys() -{ } - - -bool LLKeyboardHeadless::handleKeyDown(const U16 key, const U32 mask) -{ return false; } +bool LLKeyboardHeadless::handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) +{ + return false; +} +bool LLKeyboardHeadless::handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) +{ + return false; +} -bool LLKeyboardHeadless::handleKeyUp(const U16 key, const U32 mask) -{ return false; } +void LLKeyboardHeadless::resetMaskKeys() +{ } MASK LLKeyboardHeadless::currentMask(bool for_mouse_event) { return MASK_NONE; } -#ifdef LL_DARWIN +#if LL_DARWIN && !LL_SDL_WINDOW void LLKeyboardHeadless::handleModifier(MASK mask) { @@ -65,6 +67,7 @@ void LLKeyboardHeadless::scanKeyboard() mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); } } + mCurScanKey = KEY_NONE; // Reset edges for next frame for (S32 key = 0; key < KEY_COUNT; key++) diff --git a/indra/llwindow/llkeyboardheadless.h b/indra/llwindow/llkeyboardheadless.h index 2528f0e3f13..364fb03fe72 100644 --- a/indra/llwindow/llkeyboardheadless.h +++ b/indra/llwindow/llkeyboardheadless.h @@ -33,15 +33,15 @@ class LLKeyboardHeadless : public LLKeyboard { public: LLKeyboardHeadless(); - /*virtual*/ ~LLKeyboardHeadless() {}; + ~LLKeyboardHeadless() = default; - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); -#ifdef LL_DARWIN - /*virtual*/ void handleModifier(MASK mask); + bool handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + bool handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + void resetMaskKeys() override; + MASK currentMask(bool for_mouse_event) override; + void scanKeyboard() override; +#if LL_DARWIN && !LL_SDL_WINDOW + void handleModifier(MASK mask) override; #endif }; diff --git a/indra/llwindow/llkeyboardmacosx.cpp b/indra/llwindow/llkeyboardmacosx.cpp index 89ff7c6d3fc..1a403e5d942 100644 --- a/indra/llwindow/llkeyboardmacosx.cpp +++ b/indra/llwindow/llkeyboardmacosx.cpp @@ -162,7 +162,7 @@ LLKeyboardMacOSX::LLKeyboardMacOSX() void LLKeyboardMacOSX::resetMaskKeys() { - U32 mask = getModifiers(); + MASK mask = getModifiers(); // MBW -- XXX -- This mirrors the operation of the Windows version of resetMaskKeys(). // It looks a bit suspicious, as it won't correct for keys that have been released. @@ -187,7 +187,7 @@ void LLKeyboardMacOSX::resetMaskKeys() } /* -static bool translateKeyMac(const U16 key, const U32 mask, KEY &outKey, U32 &outMask) +static bool translateKeyMac(const U16 key, const MASK mask, KEY &outKey, U32 &outMask) { // Translate the virtual keycode into the keycodes the keyboard system expects. U16 virtualKey = (mask >> 24) & 0x0000007F; @@ -203,7 +203,7 @@ void LLKeyboardMacOSX::handleModifier(MASK mask) updateModifiers(mask); } -MASK LLKeyboardMacOSX::updateModifiers(const U32 mask) +MASK LLKeyboardMacOSX::updateModifiers(const MASK mask) { // translate the mask MASK out_mask = 0; @@ -226,7 +226,7 @@ MASK LLKeyboardMacOSX::updateModifiers(const U32 mask) return out_mask; } -bool LLKeyboardMacOSX::handleKeyDown(const U16 key, const U32 mask) +bool LLKeyboardMacOSX::handleKeyDown(const U16 key, MASK mask) { KEY translated_key = 0; U32 translated_mask = 0; @@ -243,7 +243,7 @@ bool LLKeyboardMacOSX::handleKeyDown(const U16 key, const U32 mask) } -bool LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask) +bool LLKeyboardMacOSX::handleKeyUp(const U16 key, MASK mask) { KEY translated_key = 0; U32 translated_mask = 0; @@ -262,7 +262,7 @@ bool LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask) MASK LLKeyboardMacOSX::currentMask(bool for_mouse_event) { MASK result = MASK_NONE; - U32 mask = getModifiers(); + MASK mask = getModifiers(); if (mask & MAC_SHIFT_KEY) result |= MASK_SHIFT; if (mask & MAC_CTRL_KEY) result |= MASK_CONTROL; @@ -291,6 +291,7 @@ void LLKeyboardMacOSX::scanKeyboard() mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); } } + mCurScanKey = KEY_NONE; // Reset edges for next frame for (key = 0; key < KEY_COUNT; key++) diff --git a/indra/llwindow/llkeyboardmacosx.h b/indra/llwindow/llkeyboardmacosx.h index 92ab5c9a85d..c824e7b7135 100644 --- a/indra/llwindow/llkeyboardmacosx.h +++ b/indra/llwindow/llkeyboardmacosx.h @@ -42,17 +42,17 @@ class LLKeyboardMacOSX : public LLKeyboard { public: LLKeyboardMacOSX(); - /*virtual*/ ~LLKeyboardMacOSX() {}; + ~LLKeyboardMacOSX() = default; - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); - /*virtual*/ void handleModifier(MASK mask); + bool handleKeyUp(const NATIVE_KEY_TYPE key, MASK mask) override; + bool handleKeyDown(const NATIVE_KEY_TYPE key, MASK mask) override; + void resetMaskKeys() override; + MASK currentMask(bool for_mouse_event) override; + void scanKeyboard() override; + void handleModifier(MASK mask) override; protected: - MASK updateModifiers(const U32 mask); + MASK updateModifiers(const MASK mask); void setModifierKeyLevel( KEY key, bool new_state ); bool translateNumpadKey( const U16 os_key, KEY *translated_key ); U16 inverseTranslateNumpadKey(const KEY translated_key); diff --git a/indra/llwindow/llkeyboardsdl.cpp b/indra/llwindow/llkeyboardsdl.cpp index 97198f0cc0e..803a5b8c23c 100644 --- a/indra/llwindow/llkeyboardsdl.cpp +++ b/indra/llwindow/llkeyboardsdl.cpp @@ -24,12 +24,11 @@ * $/LicenseInfo$ */ -#if LL_SDL - #include "linden_common.h" #include "llkeyboardsdl.h" #include "llwindowcallbacks.h" -#include "SDL/SDL.h" + +#include "SDL3/SDL_keycode.h" LLKeyboardSDL::LLKeyboardSDL() { @@ -40,7 +39,7 @@ LLKeyboardSDL::LLKeyboardSDL() // Virtual key mappings from SDL_keysym.h ... // SDL maps the letter keys to the ASCII you'd expect, but it's lowercase... - U16 cur_char; + LLKeyboard::NATIVE_KEY_TYPE cur_char; for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) { mTranslateKeyMap[cur_char] = cur_char; @@ -74,7 +73,6 @@ LLKeyboardSDL::LLKeyboardSDL() mTranslateKeyMap[SDLK_RIGHT] = KEY_RIGHT; mTranslateKeyMap[SDLK_UP] = KEY_UP; mTranslateKeyMap[SDLK_DOWN] = KEY_DOWN; - mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; mTranslateKeyMap[SDLK_KP_ENTER] = KEY_RETURN; mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; mTranslateKeyMap[SDLK_BACKSPACE] = KEY_BACKSPACE; @@ -115,36 +113,35 @@ LLKeyboardSDL::LLKeyboardSDL() mTranslateKeyMap[SDLK_COMMA] = ','; mTranslateKeyMap[SDLK_MINUS] = '-'; mTranslateKeyMap[SDLK_PERIOD] = '.'; - mTranslateKeyMap[SDLK_BACKQUOTE] = '`'; + mTranslateKeyMap[SDLK_GRAVE] = '`'; mTranslateKeyMap[SDLK_SLASH] = KEY_DIVIDE; mTranslateKeyMap[SDLK_SEMICOLON] = ';'; mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; - mTranslateKeyMap[SDLK_QUOTE] = '\''; + mTranslateKeyMap[SDLK_APOSTROPHE] = '\''; // Build inverse map - std::map::iterator iter; - for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) + for (auto iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) { mInvTranslateKeyMap[iter->second] = iter->first; } // numpad map - mTranslateNumpadMap[SDLK_KP0] = KEY_PAD_INS; - mTranslateNumpadMap[SDLK_KP1] = KEY_PAD_END; - mTranslateNumpadMap[SDLK_KP2] = KEY_PAD_DOWN; - mTranslateNumpadMap[SDLK_KP3] = KEY_PAD_PGDN; - mTranslateNumpadMap[SDLK_KP4] = KEY_PAD_LEFT; - mTranslateNumpadMap[SDLK_KP5] = KEY_PAD_CENTER; - mTranslateNumpadMap[SDLK_KP6] = KEY_PAD_RIGHT; - mTranslateNumpadMap[SDLK_KP7] = KEY_PAD_HOME; - mTranslateNumpadMap[SDLK_KP8] = KEY_PAD_UP; - mTranslateNumpadMap[SDLK_KP9] = KEY_PAD_PGUP; + mTranslateNumpadMap[SDLK_KP_0] = KEY_PAD_INS; + mTranslateNumpadMap[SDLK_KP_1] = KEY_PAD_END; + mTranslateNumpadMap[SDLK_KP_2] = KEY_PAD_DOWN; + mTranslateNumpadMap[SDLK_KP_3] = KEY_PAD_PGDN; + mTranslateNumpadMap[SDLK_KP_4] = KEY_PAD_LEFT; + mTranslateNumpadMap[SDLK_KP_5] = KEY_PAD_CENTER; + mTranslateNumpadMap[SDLK_KP_6] = KEY_PAD_RIGHT; + mTranslateNumpadMap[SDLK_KP_7] = KEY_PAD_HOME; + mTranslateNumpadMap[SDLK_KP_8] = KEY_PAD_UP; + mTranslateNumpadMap[SDLK_KP_9] = KEY_PAD_PGUP; mTranslateNumpadMap[SDLK_KP_PERIOD] = KEY_PAD_DEL; // build inverse numpad map - for (iter = mTranslateNumpadMap.begin(); + for (auto iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++) { @@ -154,45 +151,45 @@ LLKeyboardSDL::LLKeyboardSDL() void LLKeyboardSDL::resetMaskKeys() { - SDLMod mask = SDL_GetModState(); + SDL_Keymod mask = SDL_GetModState(); // MBW -- XXX -- This mirrors the operation of the Windows version of resetMaskKeys(). // It looks a bit suspicious, as it won't correct for keys that have been released. // Is this the way it's supposed to work? - if(mask & KMOD_SHIFT) + if(mask & SDL_KMOD_SHIFT) { mKeyLevel[KEY_SHIFT] = true; } - if(mask & KMOD_CTRL) + if(mask & SDL_KMOD_CTRL) { mKeyLevel[KEY_CONTROL] = true; } - if(mask & KMOD_ALT) + if(mask & SDL_KMOD_ALT) { mKeyLevel[KEY_ALT] = true; } } -MASK LLKeyboardSDL::updateModifiers(const U32 mask) +MASK LLKeyboardSDL::updateModifiers(const MASK mask) { // translate the mask MASK out_mask = MASK_NONE; - if(mask & KMOD_SHIFT) + if(mask & SDL_KMOD_SHIFT) { out_mask |= MASK_SHIFT; } - if(mask & KMOD_CTRL) + if(mask & SDL_KMOD_CTRL) { out_mask |= MASK_CONTROL; } - if(mask & KMOD_ALT) + if(mask & SDL_KMOD_ALT) { out_mask |= MASK_ALT; } @@ -201,37 +198,37 @@ MASK LLKeyboardSDL::updateModifiers(const U32 mask) } -static U16 adjustNativekeyFromUnhandledMask(const U16 key, const U32 mask) +LLKeyboard::NATIVE_KEY_TYPE adjustNativekeyFromUnhandledMask(const LLKeyboard::NATIVE_KEY_TYPE key, const MASK mask) { // SDL doesn't automatically adjust the keysym according to // whether NUMLOCK is engaged, so we massage the keysym manually. - U16 rtn = key; - if (!(mask & KMOD_NUM)) + LLKeyboard::NATIVE_KEY_TYPE rtn = key; + if (!(mask & SDL_KMOD_NUM)) { switch (key) { - case SDLK_KP_PERIOD: rtn = SDLK_DELETE; break; - case SDLK_KP0: rtn = SDLK_INSERT; break; - case SDLK_KP1: rtn = SDLK_END; break; - case SDLK_KP2: rtn = SDLK_DOWN; break; - case SDLK_KP3: rtn = SDLK_PAGEDOWN; break; - case SDLK_KP4: rtn = SDLK_LEFT; break; - case SDLK_KP6: rtn = SDLK_RIGHT; break; - case SDLK_KP7: rtn = SDLK_HOME; break; - case SDLK_KP8: rtn = SDLK_UP; break; - case SDLK_KP9: rtn = SDLK_PAGEUP; break; + case SDLK_KP_PERIOD: rtn = SDLK_DELETE; break; + case SDLK_KP_0: rtn = SDLK_INSERT; break; + case SDLK_KP_1: rtn = SDLK_END; break; + case SDLK_KP_2: rtn = SDLK_DOWN; break; + case SDLK_KP_3: rtn = SDLK_PAGEDOWN; break; + case SDLK_KP_4: rtn = SDLK_LEFT; break; + case SDLK_KP_6: rtn = SDLK_RIGHT; break; + case SDLK_KP_7: rtn = SDLK_HOME; break; + case SDLK_KP_8: rtn = SDLK_UP; break; + case SDLK_KP_9: rtn = SDLK_PAGEUP; break; } } return rtn; } -bool LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask) +bool LLKeyboardSDL::handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, const MASK mask) { - U16 adjusted_nativekey; + LLKeyboard::NATIVE_KEY_TYPE adjusted_nativekey; KEY translated_key = 0; - U32 translated_mask = MASK_NONE; - bool handled = false; + MASK translated_mask = MASK_NONE; + bool handled = false; adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); @@ -246,12 +243,12 @@ bool LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask) } -bool LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) +bool LLKeyboardSDL::handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, const MASK mask) { - U16 adjusted_nativekey; + LLKeyboard::NATIVE_KEY_TYPE adjusted_nativekey; KEY translated_key = 0; U32 translated_mask = MASK_NONE; - bool handled = false; + bool handled = false; adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); @@ -268,16 +265,20 @@ bool LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) MASK LLKeyboardSDL::currentMask(bool for_mouse_event) { MASK result = MASK_NONE; - SDLMod mask = SDL_GetModState(); + SDL_Keymod mask = SDL_GetModState(); - if (mask & KMOD_SHIFT) result |= MASK_SHIFT; - if (mask & KMOD_CTRL) result |= MASK_CONTROL; - if (mask & KMOD_ALT) result |= MASK_ALT; + if (mask & SDL_KMOD_SHIFT) + result |= MASK_SHIFT; + if (mask & SDL_KMOD_CTRL) + result |= MASK_CONTROL; + if (mask & SDL_KMOD_ALT) + result |= MASK_ALT; // For keyboard events, consider Meta keys equivalent to Control if (!for_mouse_event) { - if (mask & KMOD_META) result |= MASK_CONTROL; + if (mask & SDL_KMOD_GUI) + result |= MASK_CONTROL; } return result; @@ -296,6 +297,7 @@ void LLKeyboardSDL::scanKeyboard() mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); } } + mCurScanKey = KEY_NONE; // Reset edges for next frame for (S32 key = 0; key < KEY_COUNT; key++) @@ -310,15 +312,347 @@ void LLKeyboardSDL::scanKeyboard() } -bool LLKeyboardSDL::translateNumpadKey( const U16 os_key, KEY *translated_key) +bool LLKeyboardSDL::translateNumpadKey( const LLKeyboard::NATIVE_KEY_TYPE os_key, KEY *translated_key) { return translateKey(os_key, translated_key); } -U16 LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key) +LLKeyboard::NATIVE_KEY_TYPE LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key) { return inverseTranslateKey(translated_key); } -#endif +enum class WindowsVK : U32 +{ + LL_VK_UNKNOWN = 0, + LL_VK_CANCEL = 0x03, + LL_VK_BACK = 0x08, + LL_VK_TAB = 0x09, + LL_VK_CLEAR = 0x0C, + LL_VK_RETURN = 0x0D, + LL_VK_SHIFT = 0x10, + LL_VK_CONTROL = 0x11, + LL_VK_MENU = 0x12, + LL_VK_PAUSE = 0x13, + LL_VK_CAPITAL = 0x14, + LL_VK_KANA = 0x15, + LL_VK_HANGUL = 0x15, + LL_VK_JUNJA = 0x17, + LL_VK_FINAL = 0x18, + LL_VK_HANJA = 0x19, + LL_VK_KANJI = 0x19, + LL_VK_ESCAPE = 0x1B, + LL_VK_CONVERT = 0x1C, + LL_VK_NONCONVERT = 0x1D, + LL_VK_ACCEPT = 0x1E, + LL_VK_MODECHANGE = 0x1F, + LL_VK_SPACE = 0x20, + LL_VK_PRIOR = 0x21, + LL_VK_NEXT = 0x22, + LL_VK_END = 0x23, + LL_VK_HOME = 0x24, + LL_VK_LEFT = 0x25, + LL_VK_UP = 0x26, + LL_VK_RIGHT = 0x27, + LL_VK_DOWN = 0x28, + LL_VK_SELECT = 0x29, + LL_VK_PRINT = 0x2A, + LL_VK_EXECUTE = 0x2B, + LL_VK_SNAPSHOT = 0x2C, + LL_VK_INSERT = 0x2D, + LL_VK_DELETE = 0x2E, + LL_VK_HELP = 0x2F, + LL_VK_0 = 0x30, + LL_VK_1 = 0x31, + LL_VK_2 = 0x32, + LL_VK_3 = 0x33, + LL_VK_4 = 0x34, + LL_VK_5 = 0x35, + LL_VK_6 = 0x36, + LL_VK_7 = 0x37, + LL_VK_8 = 0x38, + LL_VK_9 = 0x39, + LL_VK_A = 0x41, + LL_VK_B = 0x42, + LL_VK_C = 0x43, + LL_VK_D = 0x44, + LL_VK_E = 0x45, + LL_VK_F = 0x46, + LL_VK_G = 0x47, + LL_VK_H = 0x48, + LL_VK_I = 0x49, + LL_VK_J = 0x4A, + LL_VK_K = 0x4B, + LL_VK_L = 0x4C, + LL_VK_M = 0x4D, + LL_VK_N = 0x4E, + LL_VK_O = 0x4F, + LL_VK_P = 0x50, + LL_VK_Q = 0x51, + LL_VK_R = 0x52, + LL_VK_S = 0x53, + LL_VK_T = 0x54, + LL_VK_U = 0x55, + LL_VK_V = 0x56, + LL_VK_W = 0x57, + LL_VK_X = 0x58, + LL_VK_Y = 0x59, + LL_VK_Z = 0x5A, + LL_VK_LWIN = 0x5B, + LL_VK_RWIN = 0x5C, + LL_VK_APPS = 0x5D, + LL_VK_SLEEP = 0x5F, + LL_VK_NUMPAD0 = 0x60, + LL_VK_NUMPAD1 = 0x61, + LL_VK_NUMPAD2 = 0x62, + LL_VK_NUMPAD3 = 0x63, + LL_VK_NUMPAD4 = 0x64, + LL_VK_NUMPAD5 = 0x65, + LL_VK_NUMPAD6 = 0x66, + LL_VK_NUMPAD7 = 0x67, + LL_VK_NUMPAD8 = 0x68, + LL_VK_NUMPAD9 = 0x69, + LL_VK_MULTIPLY = 0x6A, + LL_VK_ADD = 0x6B, + LL_VK_SEPARATOR = 0x6C, + LL_VK_SUBTRACT = 0x6D, + LL_VK_DECIMAL = 0x6E, + LL_VK_DIVIDE = 0x6F, + LL_VK_F1 = 0x70, + LL_VK_F2 = 0x71, + LL_VK_F3 = 0x72, + LL_VK_F4 = 0x73, + LL_VK_F5 = 0x74, + LL_VK_F6 = 0x75, + LL_VK_F7 = 0x76, + LL_VK_F8 = 0x77, + LL_VK_F9 = 0x78, + LL_VK_F10 = 0x79, + LL_VK_F11 = 0x7A, + LL_VK_F12 = 0x7B, + LL_VK_F13 = 0x7C, + LL_VK_F14 = 0x7D, + LL_VK_F15 = 0x7E, + LL_VK_F16 = 0x7F, + LL_VK_F17 = 0x80, + LL_VK_F18 = 0x81, + LL_VK_F19 = 0x82, + LL_VK_F20 = 0x83, + LL_VK_F21 = 0x84, + LL_VK_F22 = 0x85, + LL_VK_F23 = 0x86, + LL_VK_F24 = 0x87, + LL_VK_NUMLOCK = 0x90, + LL_VK_SCROLL = 0x91, + LL_VK_LSHIFT = 0xA0, + LL_VK_RSHIFT = 0xA1, + LL_VK_LCONTROL = 0xA2, + LL_VK_RCONTROL = 0xA3, + LL_VK_LMENU = 0xA4, + LL_VK_RMENU = 0xA5, + LL_VK_BROWSER_BACK = 0xA6, + LL_VK_BROWSER_FORWARD = 0xA7, + LL_VK_BROWSER_REFRESH = 0xA8, + LL_VK_BROWSER_STOP = 0xA9, + LL_VK_BROWSER_SEARCH = 0xAA, + LL_VK_BROWSER_FAVORITES = 0xAB, + LL_VK_BROWSER_HOME = 0xAC, + LL_VK_VOLUME_MUTE = 0xAD, + LL_VK_VOLUME_DOWN = 0xAE, + LL_VK_VOLUME_UP = 0xAF, + LL_VK_MEDIA_NEXT_TRACK = 0xB0, + LL_VK_MEDIA_PREV_TRACK = 0xB1, + LL_VK_MEDIA_STOP = 0xB2, + LL_VK_MEDIA_PLAY_PAUSE = 0xB3, + LL_VK_MEDIA_LAUNCH_MAIL = 0xB4, + LL_VK_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5, + LL_VK_MEDIA_LAUNCH_APP1 = 0xB6, + LL_VK_MEDIA_LAUNCH_APP2 = 0xB7, + LL_VK_OEM_1 = 0xBA, + LL_VK_OEM_PLUS = 0xBB, + LL_VK_OEM_COMMA = 0xBC, + LL_VK_OEM_MINUS = 0xBD, + LL_VK_OEM_PERIOD = 0xBE, + LL_VK_OEM_2 = 0xBF, + LL_VK_OEM_3 = 0xC0, + LL_VK_OEM_4 = 0xDB, + LL_VK_OEM_5 = 0xDC, + LL_VK_OEM_6 = 0xDD, + LL_VK_OEM_7 = 0xDE, + LL_VK_OEM_8 = 0xDF, + LL_VK_OEM_102 = 0xE2, + LL_VK_PROCESSKEY = 0xE5, + LL_VK_PACKET = 0xE7, + LL_VK_ATTN = 0xF6, + LL_VK_CRSEL = 0xF7, + LL_VK_EXSEL = 0xF8, + LL_VK_EREOF = 0xF9, + LL_VK_PLAY = 0xFA, + LL_VK_ZOOM = 0xFB, + LL_VK_NONAME = 0xFC, + LL_VK_PA1 = 0xFD, + LL_VK_OEM_CLEAR = 0xFE, +}; + +std::map< U32, U32 > mSDL2_to_Win; + +U32 LLKeyboardSDL::mapSDL2toWin( U32 aSymbol ) +{ + // Map SDLK_ virtual keys to Windows LL_VK_ virtual keys. + // Text is handled via unicode input (SDL_TEXTINPUT event) and does not need to be translated into LL_VK_ values as those match already. + if( mSDL2_to_Win.empty() ) + { + + mSDL2_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::LL_VK_BACK; + mSDL2_to_Win[ SDLK_TAB ] = (U32)WindowsVK::LL_VK_TAB; + mSDL2_to_Win[ 12 ] = (U32)WindowsVK::LL_VK_CLEAR; + mSDL2_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::LL_VK_RETURN; + mSDL2_to_Win[ 19 ] = (U32)WindowsVK::LL_VK_PAUSE; + mSDL2_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::LL_VK_ESCAPE; + mSDL2_to_Win[ SDLK_SPACE ] = (U32)WindowsVK::LL_VK_SPACE; + mSDL2_to_Win[ SDLK_APOSTROPHE ] = (U32)WindowsVK::LL_VK_OEM_7; + mSDL2_to_Win[ SDLK_COMMA ] = (U32)WindowsVK::LL_VK_OEM_COMMA; + mSDL2_to_Win[ SDLK_MINUS ] = (U32)WindowsVK::LL_VK_OEM_MINUS; + mSDL2_to_Win[ SDLK_PERIOD ] = (U32)WindowsVK::LL_VK_OEM_PERIOD; + mSDL2_to_Win[ SDLK_SLASH ] = (U32)WindowsVK::LL_VK_OEM_2; + + mSDL2_to_Win[ SDLK_0 ] = (U32)WindowsVK::LL_VK_0; + mSDL2_to_Win[ SDLK_1 ] = (U32)WindowsVK::LL_VK_1; + mSDL2_to_Win[ SDLK_2 ] = (U32)WindowsVK::LL_VK_2; + mSDL2_to_Win[ SDLK_3 ] = (U32)WindowsVK::LL_VK_3; + mSDL2_to_Win[ SDLK_4 ] = (U32)WindowsVK::LL_VK_4; + mSDL2_to_Win[ SDLK_5 ] = (U32)WindowsVK::LL_VK_5; + mSDL2_to_Win[ SDLK_6 ] = (U32)WindowsVK::LL_VK_6; + mSDL2_to_Win[ SDLK_7 ] = (U32)WindowsVK::LL_VK_7; + mSDL2_to_Win[ SDLK_8 ] = (U32)WindowsVK::LL_VK_8; + mSDL2_to_Win[ SDLK_9 ] = (U32)WindowsVK::LL_VK_9; + + mSDL2_to_Win[ SDLK_SEMICOLON ] = (U32)WindowsVK::LL_VK_OEM_1; + mSDL2_to_Win[ SDLK_LESS ] = (U32)WindowsVK::LL_VK_OEM_102; + mSDL2_to_Win[ SDLK_EQUALS ] = (U32)WindowsVK::LL_VK_OEM_PLUS; + mSDL2_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::LL_VK_OEM_PLUS; + + mSDL2_to_Win[ SDLK_LEFTBRACKET ] = (U32)WindowsVK::LL_VK_OEM_4; + mSDL2_to_Win[ SDLK_BACKSLASH ] = (U32)WindowsVK::LL_VK_OEM_5; + mSDL2_to_Win[ SDLK_RIGHTBRACKET ] = (U32)WindowsVK::LL_VK_OEM_6; + mSDL2_to_Win[ SDLK_GRAVE ] = (U32)WindowsVK::LL_VK_OEM_8; + + mSDL2_to_Win[ SDLK_A ] = (U32)WindowsVK::LL_VK_A; + mSDL2_to_Win[ SDLK_B ] = (U32)WindowsVK::LL_VK_B; + mSDL2_to_Win[ SDLK_C ] = (U32)WindowsVK::LL_VK_C; + mSDL2_to_Win[ SDLK_D ] = (U32)WindowsVK::LL_VK_D; + mSDL2_to_Win[ SDLK_E ] = (U32)WindowsVK::LL_VK_E; + mSDL2_to_Win[ SDLK_F ] = (U32)WindowsVK::LL_VK_F; + mSDL2_to_Win[ SDLK_G ] = (U32)WindowsVK::LL_VK_G; + mSDL2_to_Win[ SDLK_H ] = (U32)WindowsVK::LL_VK_H; + mSDL2_to_Win[ SDLK_I ] = (U32)WindowsVK::LL_VK_I; + mSDL2_to_Win[ SDLK_J ] = (U32)WindowsVK::LL_VK_J; + mSDL2_to_Win[ SDLK_K ] = (U32)WindowsVK::LL_VK_K; + mSDL2_to_Win[ SDLK_L ] = (U32)WindowsVK::LL_VK_L; + mSDL2_to_Win[ SDLK_M ] = (U32)WindowsVK::LL_VK_M; + mSDL2_to_Win[ SDLK_N ] = (U32)WindowsVK::LL_VK_N; + mSDL2_to_Win[ SDLK_O ] = (U32)WindowsVK::LL_VK_O; + mSDL2_to_Win[ SDLK_P ] = (U32)WindowsVK::LL_VK_P; + mSDL2_to_Win[ SDLK_Q ] = (U32)WindowsVK::LL_VK_Q; + mSDL2_to_Win[ SDLK_R ] = (U32)WindowsVK::LL_VK_R; + mSDL2_to_Win[ SDLK_S ] = (U32)WindowsVK::LL_VK_S; + mSDL2_to_Win[ SDLK_T ] = (U32)WindowsVK::LL_VK_T; + mSDL2_to_Win[ SDLK_Y ] = (U32)WindowsVK::LL_VK_U; + mSDL2_to_Win[ SDLK_V ] = (U32)WindowsVK::LL_VK_V; + mSDL2_to_Win[ SDLK_W ] = (U32)WindowsVK::LL_VK_W; + mSDL2_to_Win[ SDLK_X ] = (U32)WindowsVK::LL_VK_X; + mSDL2_to_Win[ SDLK_Y ] = (U32)WindowsVK::LL_VK_Y; + mSDL2_to_Win[ SDLK_Z ] = (U32)WindowsVK::LL_VK_Z; + + mSDL2_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::LL_VK_DELETE; + + + mSDL2_to_Win[ SDLK_NUMLOCKCLEAR ] = (U32)WindowsVK::LL_VK_NUMLOCK; + mSDL2_to_Win[ SDLK_SCROLLLOCK ] = (U32)WindowsVK::LL_VK_SCROLL; + + mSDL2_to_Win[ SDLK_HELP ] = (U32)WindowsVK::LL_VK_HELP; + mSDL2_to_Win[ SDLK_PRINTSCREEN ] = (U32)WindowsVK::LL_VK_SNAPSHOT; + mSDL2_to_Win[ SDLK_CANCEL ] = (U32)WindowsVK::LL_VK_CANCEL; + mSDL2_to_Win[ SDLK_APPLICATION ] = (U32)WindowsVK::LL_VK_APPS; + + mSDL2_to_Win[ SDLK_UNKNOWN ] = (U32)WindowsVK::LL_VK_UNKNOWN; + mSDL2_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::LL_VK_BACK; + mSDL2_to_Win[ SDLK_TAB ] = (U32)WindowsVK::LL_VK_TAB; + mSDL2_to_Win[ SDLK_CLEAR ] = (U32)WindowsVK::LL_VK_CLEAR; + mSDL2_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::LL_VK_RETURN; + mSDL2_to_Win[ SDLK_PAUSE ] = (U32)WindowsVK::LL_VK_PAUSE; + mSDL2_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::LL_VK_ESCAPE; + mSDL2_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::LL_VK_DELETE; + + mSDL2_to_Win[ SDLK_KP_PERIOD ] = (U32)WindowsVK::LL_VK_DELETE; // LL_VK_DECIMAL? + mSDL2_to_Win[ SDLK_KP_DIVIDE ] = (U32)WindowsVK::LL_VK_DIVIDE; + mSDL2_to_Win[ SDLK_KP_MULTIPLY] = (U32)WindowsVK::LL_VK_MULTIPLY; + mSDL2_to_Win[ SDLK_KP_MINUS ] = (U32)WindowsVK::LL_VK_OEM_MINUS; // LL_VK_SUBSTRACT? + mSDL2_to_Win[ SDLK_KP_PLUS ] = (U32)WindowsVK::LL_VK_OEM_PLUS; // LL_VK_ADD? + mSDL2_to_Win[ SDLK_KP_ENTER ] = (U32)WindowsVK::LL_VK_RETURN; + mSDL2_to_Win[ SDLK_KP_0 ] = (U32)WindowsVK::LL_VK_INSERT; + mSDL2_to_Win[ SDLK_KP_1 ] = (U32)WindowsVK::LL_VK_END; + mSDL2_to_Win[ SDLK_KP_2 ] = (U32)WindowsVK::LL_VK_DOWN; + mSDL2_to_Win[ SDLK_KP_3 ] = (U32)WindowsVK::LL_VK_NEXT; + mSDL2_to_Win[ SDLK_KP_4 ] = (U32)WindowsVK::LL_VK_LEFT; + mSDL2_to_Win[ SDLK_KP_5 ] = (U32)WindowsVK::LL_VK_NUMPAD5; + mSDL2_to_Win[ SDLK_KP_6 ] = (U32)WindowsVK::LL_VK_RIGHT; + mSDL2_to_Win[ SDLK_KP_7 ] = (U32)WindowsVK::LL_VK_HOME; + mSDL2_to_Win[ SDLK_KP_8 ] = (U32)WindowsVK::LL_VK_UP; + mSDL2_to_Win[ SDLK_KP_9 ] = (U32)WindowsVK::LL_VK_PRIOR; + + // ? + + mSDL2_to_Win[ SDLK_UP ] = (U32)WindowsVK::LL_VK_UP; + mSDL2_to_Win[ SDLK_DOWN ] = (U32)WindowsVK::LL_VK_DOWN; + mSDL2_to_Win[ SDLK_RIGHT ] = (U32)WindowsVK::LL_VK_RIGHT; + mSDL2_to_Win[ SDLK_LEFT ] = (U32)WindowsVK::LL_VK_LEFT; + mSDL2_to_Win[ SDLK_INSERT ] = (U32)WindowsVK::LL_VK_INSERT; + mSDL2_to_Win[ SDLK_HOME ] = (U32)WindowsVK::LL_VK_HOME; + mSDL2_to_Win[ SDLK_END ] = (U32)WindowsVK::LL_VK_END; + mSDL2_to_Win[ SDLK_PAGEUP ] = (U32)WindowsVK::LL_VK_PRIOR; + mSDL2_to_Win[ SDLK_PAGEDOWN ] = (U32)WindowsVK::LL_VK_NEXT; + mSDL2_to_Win[ SDLK_F1 ] = (U32)WindowsVK::LL_VK_F1; + mSDL2_to_Win[ SDLK_F2 ] = (U32)WindowsVK::LL_VK_F2; + mSDL2_to_Win[ SDLK_F3 ] = (U32)WindowsVK::LL_VK_F3; + mSDL2_to_Win[ SDLK_F4 ] = (U32)WindowsVK::LL_VK_F4; + mSDL2_to_Win[ SDLK_F5 ] = (U32)WindowsVK::LL_VK_F5; + mSDL2_to_Win[ SDLK_F6 ] = (U32)WindowsVK::LL_VK_F6; + mSDL2_to_Win[ SDLK_F7 ] = (U32)WindowsVK::LL_VK_F7; + mSDL2_to_Win[ SDLK_F8 ] = (U32)WindowsVK::LL_VK_F8; + mSDL2_to_Win[ SDLK_F9 ] = (U32)WindowsVK::LL_VK_F9; + mSDL2_to_Win[ SDLK_F10 ] = (U32)WindowsVK::LL_VK_F10; + mSDL2_to_Win[ SDLK_F11 ] = (U32)WindowsVK::LL_VK_F11; + mSDL2_to_Win[ SDLK_F12 ] = (U32)WindowsVK::LL_VK_F12; + mSDL2_to_Win[ SDLK_F13 ] = (U32)WindowsVK::LL_VK_F13; + mSDL2_to_Win[ SDLK_F14 ] = (U32)WindowsVK::LL_VK_F14; + mSDL2_to_Win[ SDLK_F15 ] = (U32)WindowsVK::LL_VK_F15; + mSDL2_to_Win[ SDLK_CAPSLOCK ] = (U32)WindowsVK::LL_VK_CAPITAL; + mSDL2_to_Win[ SDLK_RSHIFT ] = (U32)WindowsVK::LL_VK_SHIFT; + mSDL2_to_Win[ SDLK_LSHIFT ] = (U32)WindowsVK::LL_VK_SHIFT; + mSDL2_to_Win[ SDLK_RCTRL ] = (U32)WindowsVK::LL_VK_CONTROL; + mSDL2_to_Win[ SDLK_LCTRL ] = (U32)WindowsVK::LL_VK_CONTROL; + mSDL2_to_Win[ SDLK_RALT ] = (U32)WindowsVK::LL_VK_MENU; + mSDL2_to_Win[ SDLK_LALT ] = (U32)WindowsVK::LL_VK_MENU; + + mSDL2_to_Win[ SDLK_MENU ] = (U32)WindowsVK::LL_VK_MENU; + + // LL_VK_MODECHANGE ? + // mSDL2_to_Win[ SDLK_MODE ] = (U32)WindowsVK::LL_VK_MODE; + + // ? + // mSDL2_to_Win[ SDLK_SYSREQ ] = (U32)WindowsVK::LL_VK_SYSREQ; + // mSDL2_to_Win[ SDLK_POWER ] = (U32)WindowsVK::LL_VK_POWER; + // mSDL2_to_Win[ SDLK_UNDO ] = (U32)WindowsVK::LL_VK_UNDO; + // mSDL2_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::LL_VK_EQUALS; + // mSDL2_to_Win[ 311 ] = (U32)WindowsVK::LL_VK_LWIN; + // mSDL2_to_Win[ 312 ] = (U32)WindowsVK::LL_VK_RWIN; + // mSDL2_to_Win[ SDLK_COLON ] = ? + } + auto itr = mSDL2_to_Win.find( aSymbol ); + if( itr != mSDL2_to_Win.end() ) + return itr->second; + + return aSymbol; +} diff --git a/indra/llwindow/llkeyboardsdl.h b/indra/llwindow/llkeyboardsdl.h index fd348b28f2a..f23b4cca6c7 100644 --- a/indra/llwindow/llkeyboardsdl.h +++ b/indra/llwindow/llkeyboardsdl.h @@ -28,28 +28,31 @@ #define LL_LLKEYBOARDSDL_H #include "llkeyboard.h" -#include "SDL/SDL.h" +#include "SDL3/SDL.h" class LLKeyboardSDL : public LLKeyboard { public: LLKeyboardSDL(); - /*virtual*/ ~LLKeyboardSDL() {}; + ~LLKeyboardSDL() = default; - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); + bool handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + bool handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + void resetMaskKeys() override; + MASK currentMask(bool for_mouse_event) override; + void scanKeyboard() override; protected: - MASK updateModifiers(const U32 mask); + MASK updateModifiers(const MASK mask); void setModifierKeyLevel( KEY key, bool new_state ); - bool translateNumpadKey( const U16 os_key, KEY *translated_key ); - U16 inverseTranslateNumpadKey(const KEY translated_key); + bool translateNumpadKey( const LLKeyboard::NATIVE_KEY_TYPE os_key, KEY *translated_key ); + LLKeyboard::NATIVE_KEY_TYPE inverseTranslateNumpadKey(const KEY translated_key); private: - std::map mTranslateNumpadMap; // special map for translating OS keys to numpad keys - std::map mInvTranslateNumpadMap; // inverse of the above + std::map mTranslateNumpadMap; // special map for translating OS keys to numpad keys + std::map mInvTranslateNumpadMap; // inverse of the above + +public: + static U32 mapSDL2toWin( U32 ); }; #endif diff --git a/indra/llwindow/llkeyboardwin32.cpp b/indra/llwindow/llkeyboardwin32.cpp index 8d6b8d9b93d..4ef0b493a57 100644 --- a/indra/llwindow/llkeyboardwin32.cpp +++ b/indra/llwindow/llkeyboardwin32.cpp @@ -197,7 +197,7 @@ MASK LLKeyboardWin32::updateModifiers() // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags -bool LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask) +bool LLKeyboardWin32::handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) { KEY translated_key; U32 translated_mask; @@ -214,7 +214,7 @@ bool LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask) } // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags -bool LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask) +bool LLKeyboardWin32::handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) { KEY translated_key; U32 translated_mask; diff --git a/indra/llwindow/llkeyboardwin32.h b/indra/llwindow/llkeyboardwin32.h index d0dfc5cfdd3..fa223a29048 100644 --- a/indra/llwindow/llkeyboardwin32.h +++ b/indra/llwindow/llkeyboardwin32.h @@ -37,15 +37,16 @@ class LLKeyboardWin32 : public LLKeyboard { public: LLKeyboardWin32(); - /*virtual*/ ~LLKeyboardWin32() {}; - - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); - bool translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key); - U16 inverseTranslateExtendedKey(const KEY translated_key); + ~LLKeyboardWin32() = default; + + bool handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + bool handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + void resetMaskKeys() override; + MASK currentMask(bool for_mouse_event) override; + void scanKeyboard() override; + + bool translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key); + U16 inverseTranslateExtendedKey(const KEY translated_key); protected: MASK updateModifiers(); diff --git a/indra/llwindow/llmousehandler.cpp b/indra/llwindow/llmousehandler.cpp index eeceab502ac..959dde70b40 100644 --- a/indra/llwindow/llmousehandler.cpp +++ b/indra/llwindow/llmousehandler.cpp @@ -24,6 +24,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llmousehandler.h" //virtual diff --git a/indra/llwindow/llsdl.cpp b/indra/llwindow/llsdl.cpp new file mode 100644 index 00000000000..1e554b2f6cd --- /dev/null +++ b/indra/llwindow/llsdl.cpp @@ -0,0 +1,142 @@ +/** + * @file llsdl.cpp + * @brief SDL2 initialization + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include +#include + +#include "SDL3/SDL.h" + +#ifndef LL_SDL_APP +#define SDL_MAIN_HANDLED 1 +#include "SDL3/SDL_main.h" +#endif + +#include "llerror.h" +#include "llwindow.h" + +void sdl_logger(void *userdata, int category, SDL_LogPriority priority, const char *message) +{ + switch (priority) + { + case SDL_LOG_PRIORITY_TRACE: + case SDL_LOG_PRIORITY_VERBOSE: + case SDL_LOG_PRIORITY_DEBUG: + LL_DEBUGS("SDL") << "log='" << message << "'" << LL_ENDL; + break; + case SDL_LOG_PRIORITY_INFO: + LL_INFOS("SDL") << "log='" << message << "'" << LL_ENDL; + break; + case SDL_LOG_PRIORITY_WARN: + case SDL_LOG_PRIORITY_ERROR: + case SDL_LOG_PRIORITY_CRITICAL: + LL_WARNS("SDL") << "log='" << message << "'" << LL_ENDL; + break; + case SDL_LOG_PRIORITY_INVALID: + default: + break; + } +} + +void init_sdl(const std::string& app_name) +{ +#ifndef LL_SDL_APP + SDL_SetMainReady(); + + SDL_SetLogOutputFunction(&sdl_logger, nullptr); +#endif + +#if LL_WINDOWS && defined(LL_SDL_WINDOW) + Uint32 style = 0; +#if defined(CS_BYTEALIGNCLIENT) && defined(CS_OWNDC) + style = (CS_BYTEALIGNCLIENT | CS_OWNDC); +#endif + SDL_RegisterApp(app_name.c_str(), style, nullptr); +#endif + + const int c_sdl_version = SDL_VERSION; + LL_INFOS() << "Compiled against SDL " + << SDL_VERSIONNUM_MAJOR(c_sdl_version) << "." + << SDL_VERSIONNUM_MINOR(c_sdl_version) << "." + << SDL_VERSIONNUM_MICRO(c_sdl_version) << LL_ENDL; + const int r_sdl_version = SDL_GetVersion(); + LL_INFOS() << "Running with SDL " + << SDL_VERSIONNUM_MAJOR(r_sdl_version) << "." + << SDL_VERSIONNUM_MINOR(r_sdl_version) << "." + << SDL_VERSIONNUM_MICRO(r_sdl_version) << LL_ENDL; + +#if LL_SDL_WINDOW + // For linux we SDL_INIT_VIDEO and _AUDIO + std::initializer_list > hintList = + { + {SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR,"0"}, + {SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH,"1"}, + {SDL_HINT_KEYCODE_OPTIONS,"hide_numpad,french_numbers,latin_letters"} + }; + + for (auto hint: hintList) + { + SDL_SetHint(std::get<0>(hint), std::get<1>(hint)); + } + + std::initializer_list> initList= + { + {SDL_INIT_VIDEO,"SDL_INIT_VIDEO", true}, + {SDL_INIT_JOYSTICK,"SDL_INIT_JOYSTICK", true}, + {SDL_INIT_GAMEPAD,"SDL_INIT_GAMEPAD", true}, + }; +#else + // For non-linux platforms we still SDL_INIT_VIDEO because it is a pre-requisite + // for SDL_INIT_GAMECONTROLLER. + std::initializer_list> initList= + { + {SDL_INIT_VIDEO,"SDL_INIT_VIDEO", false}, + }; +#endif // LL_LINUX + // We SDL_INIT_GAMECONTROLLER later in the startup process to make it + // more likely we'll catch initial SDL_CONTROLLERDEVICEADDED events. + + for (auto subSystem : initList) + { + if (!SDL_InitSubSystem(std::get<0>(subSystem))) + { + LL_WARNS() << "SDL_InitSubSystem for " << std::get<1>(subSystem) << " failed " << SDL_GetError() << LL_ENDL; + + if (std::get<2>(subSystem)) + { + OSMessageBox("SDL_Init() failure", "error", OSMB_OK); + return; + } + } + } +} + +void quit_sdl() +{ +#if LL_WINDOWS && defined(LL_SDL_WINDOW) + SDL_UnregisterApp(); +#endif + SDL_Quit(); +} diff --git a/indra/newview/llappviewerlinux_api_dbus.h b/indra/llwindow/llsdl.h similarity index 62% rename from indra/newview/llappviewerlinux_api_dbus.h rename to indra/llwindow/llsdl.h index 2f4492bd7ae..b3e84fbc5dd 100644 --- a/indra/newview/llappviewerlinux_api_dbus.h +++ b/indra/llwindow/llsdl.h @@ -1,8 +1,8 @@ /** - * @file llappviewerlinux_api_dbus.h - * @brief DBus-glib symbol handling + * @file llsdl.h + * @brief SDL2 initialization * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * @@ -24,21 +24,7 @@ * $/LicenseInfo$ */ -#include "linden_common.h" +#pragma once -#if LL_DBUS_ENABLED - -extern "C" { -#include -} - -#define DBUSGLIB_DYLIB_DEFAULT_NAME "libdbus-glib-1.so.2" - -bool grab_dbus_syms(std::string dbus_dso_name); -void ungrab_dbus_syms(); - -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) extern RTN (*ll##DBUSSYM)(__VA_ARGS__) -#include "llappviewerlinux_api_dbus_syms_raw.inc" -#undef LL_DBUS_SYM - -#endif // LL_DBUS_ENABLED +void init_sdl(const std::string& app_name); +void quit_sdl(); diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index eb11a283602..2313aeda50c 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -29,7 +29,7 @@ #if LL_MESA_HEADLESS #include "llwindowmesaheadless.h" -#elif LL_SDL +#elif LL_SDL_WINDOW #include "llwindowsdl.h" #elif LL_WINDOWS #include "llwindowwin32.h" @@ -39,6 +39,9 @@ #include "llerror.h" #include "llkeyboard.h" +#if LL_SDL_WINDOW && !defined(LL_MESA_HEADLESS) +#include "llsdl.h" +#endif #include "llwindowcallbacks.h" @@ -74,14 +77,15 @@ S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type) LL_WARNS() << "OSMessageBox: " << text << LL_ENDL; #if LL_MESA_HEADLESS // !!! *FIX: (?) return OSBTN_OK; +#elif LL_SDL_WINDOW + result = OSMessageBoxSDL(text, caption, type); #elif LL_WINDOWS result = OSMessageBoxWin32(text, caption, type); #elif LL_DARWIN result = OSMessageBoxMacOSX(text, caption, type); -#elif LL_SDL - result = OSMessageBoxSDL(text, caption, type); #else -#error("OSMessageBox not implemented for this platform!") + LL_WARNS() << "OSMessageBox not implemented for this platform!" << LL_ENDL; + return OSBTN_OK; #endif if (was_visible) @@ -182,12 +186,6 @@ bool LLWindow::dialogColorPicker(F32 *r, F32 *g, F32 *b) return false; } -void *LLWindow::getMediaWindow() -{ - // Default to returning the platform window. - return getPlatformWindow(); -} - bool LLWindow::setSize(LLCoordScreen size) { if (!getMaximized()) @@ -258,12 +256,12 @@ bool LLWindow::copyTextToPrimary(const LLWString &src) // static std::vector LLWindow::getDynamicFallbackFontList() { -#if LL_WINDOWS +#if LL_SDL_WINDOW && !LL_MESA_HEADLESS + return LLWindowSDL::getDynamicFallbackFontList(); +#elif LL_WINDOWS return LLWindowWin32::getDynamicFallbackFontList(); #elif LL_DARWIN return LLWindowMacOSX::getDynamicFallbackFontList(); -#elif LL_SDL - return LLWindowSDL::getDynamicFallbackFontList(); #else return std::vector(); #endif @@ -272,7 +270,9 @@ std::vector LLWindow::getDynamicFallbackFontList() // static std::vector LLWindow::getDisplaysResolutionList() { -#if LL_WINDOWS +#if LL_SDL_WINDOW && !LL_MESA_HEADLESS + return LLWindowSDL::getDisplaysResolutionList(); +#elif LL_WINDOWS return LLWindowWin32::getDisplaysResolutionList(); #elif LL_DARWIN return LLWindowMacOSX::getDisplaysResolutionList(); @@ -341,14 +341,17 @@ bool LLSplashScreen::isVisible() // static LLSplashScreen *LLSplashScreen::create() { -#if LL_MESA_HEADLESS || LL_SDL // !!! *FIX: (?) - return 0; +#if LL_MESA_HEADLESS + return nullptr; +#elif LL_SDL_WINDOW + return new LLSplashScreenSDL; #elif LL_WINDOWS return new LLSplashScreenWin32; #elif LL_DARWIN return new LLSplashScreenMacOSX; #else -#error("LLSplashScreen not implemented on this platform!") + LL_WARNS() << ("LLSplashScreen not implemented on this platform!") << LL_ENDL; + return nullptr; #endif } @@ -358,7 +361,9 @@ void LLSplashScreen::show() { if (!gSplashScreenp) { -#if LL_WINDOWS && !LL_MESA_HEADLESS +#if LL_SDL_WINDOW && !LL_MESA_HEADLESS + gSplashScreenp = new LLSplashScreenSDL; +#elif LL_WINDOWS && !LL_MESA_HEADLESS gSplashScreenp = new LLSplashScreenWin32; #elif LL_DARWIN gSplashScreenp = new LLSplashScreenMacOSX; @@ -412,15 +417,19 @@ LLWindow* LLWindowManager::createWindow( { LLWindow* new_window; +#if LL_SDL_WINDOW && !defined(LL_MESA_HEADLESS) + init_sdl(name); +#endif + if (use_gl) { #if LL_MESA_HEADLESS new_window = new LLWindowMesaHeadless(callbacks, title, name, x, y, width, height, flags, fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth); -#elif LL_SDL +#elif LL_SDL_WINDOW new_window = new LLWindowSDL(callbacks, - title, x, y, width, height, flags, + title, name, x, y, width, height, flags, fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); #elif LL_WINDOWS new_window = new LLWindowWin32(callbacks, @@ -461,6 +470,9 @@ bool LLWindowManager::destroyWindow(LLWindow* window) window->close(); sWindowList.erase(window); +#if LL_SDL_WINDOW && !defined(LL_MESA_HEADLESS) + quit_sdl(); +#endif delete window; diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 7a5404e6154..2d8fc80b9ea 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -92,7 +92,7 @@ class LLWindow : public LLInstanceTracker virtual bool setCursorPosition(LLCoordWindow position) = 0; virtual bool getCursorPosition(LLCoordWindow *position) = 0; -#if LL_WINDOWS +#if LL_WINDOWS && !LL_SDL_WINDOW virtual bool getCursorDelta(LLCoordCommon* delta) = 0; #endif virtual bool isWrapMouse() const = 0; @@ -174,9 +174,6 @@ class LLWindow : public LLInstanceTracker // return a platform-specific window reference (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) virtual void *getPlatformWindow() = 0; -// return the platform-specific window reference we use to initialize llmozlib (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) - virtual void *getMediaWindow(); - // control platform's Language Text Input mechanisms. virtual void allowLanguageTextInput(LLPreeditor *preeditor, bool b) {} virtual void setLanguageTextInput( const LLCoordGL & pos ) {}; diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index dc7b833013d..8b7b0ef55c6 100644 --- a/indra/llwindow/llwindowheadless.h +++ b/indra/llwindow/llwindowheadless.h @@ -60,7 +60,7 @@ class LLWindowHeadless : public LLWindow /*virtual*/ void toggleVSync(bool enable_vsync) override { } /*virtual*/ bool setCursorPosition(LLCoordWindow position) override {return false;} /*virtual*/ bool getCursorPosition(LLCoordWindow *position) override {return false;} -#if LL_WINDOWS +#if LL_WINDOWS && !LL_SDL_WINDOW /*virtual*/ bool getCursorDelta(LLCoordCommon* delta) override { return false; } #endif /*virtual*/ bool isWrapMouse() const override { return true; } diff --git a/indra/llwindow/llwindowmesaheadless.h b/indra/llwindow/llwindowmesaheadless.h index 0bf8c46a30b..47cd6320b1e 100644 --- a/indra/llwindow/llwindowmesaheadless.h +++ b/indra/llwindow/llwindowmesaheadless.h @@ -30,70 +30,75 @@ #if LL_MESA_HEADLESS #include "llwindow.h" -#include "GL/glu.h" #include "GL/osmesa.h" class LLWindowMesaHeadless : public LLWindow { public: - /*virtual*/ void show() {}; - /*virtual*/ void hide() {}; - /*virtual*/ void close() {}; - /*virtual*/ bool getVisible() {return false;}; - /*virtual*/ bool getMinimized() {return false;}; - /*virtual*/ bool getMaximized() {return false;}; - /*virtual*/ bool maximize() {return false;}; - /*virtual*/ void minimize() {}; - /*virtual*/ void restore() {}; - /*virtual*/ bool getFullscreen() {return false;}; - /*virtual*/ bool getPosition(LLCoordScreen *position) {return false;}; - /*virtual*/ bool getSize(LLCoordScreen *size) {return false;}; - /*virtual*/ bool getSize(LLCoordWindow *size) {return false;}; - /*virtual*/ bool setPosition(LLCoordScreen position) {return false;}; - /*virtual*/ bool setSizeImpl(LLCoordScreen size) {return false;}; - /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool disable_vsync, const LLCoordScreen * const posp = NULL) {return false;}; - /*virtual*/ bool setCursorPosition(LLCoordWindow position) {return false;}; - /*virtual*/ bool getCursorPosition(LLCoordWindow *position) {return false;}; - /*virtual*/ void showCursor() {}; - /*virtual*/ void hideCursor() {}; - /*virtual*/ void showCursorFromMouseMove() {}; - /*virtual*/ void hideCursorUntilMouseMove() {}; - /*virtual*/ bool isCursorHidden() {return false;}; - /*virtual*/ void updateCursor() {}; - //virtual ECursorType getCursor() { return mCurrentCursor; }; - /*virtual*/ void captureMouse() {}; - /*virtual*/ void releaseMouse() {}; - /*virtual*/ void setMouseClipping( bool b ) {}; - /*virtual*/ bool isClipboardTextAvailable() {return false; }; - /*virtual*/ bool pasteTextFromClipboard(LLWString &dst) {return false; }; - /*virtual*/ bool copyTextToClipboard(const LLWString &src) {return false; }; - /*virtual*/ void flashIcon(F32 seconds) {}; - /*virtual*/ F32 getGamma() {return 1.0f; }; - /*virtual*/ bool setGamma(const F32 gamma) {return false; }; // Set the gamma - /*virtual*/ bool restoreGamma() {return false; }; // Restore original gamma table (before updating gamma) - /*virtual*/ void setFSAASamples(const U32 fsaa_samples) { /* FSAA not supported yet on Mesa headless.*/ } - /*virtual*/ U32 getFSAASamples() { return 0; } - //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } - /*virtual*/ void gatherInput() {}; - /*virtual*/ void delayInputProcessing() {}; - /*virtual*/ void swapBuffers(); - /*virtual*/ void restoreGLContext() {}; + void show() override {}; + void hide() override {}; + void close() override {}; + bool getVisible() override {return false;}; + bool getMinimized() override {return false;}; + bool getMaximized() override {return false;}; + bool maximize() override {return false;}; + void minimize() override {}; + void restore() override {}; + bool getFullscreen() {return false;}; + bool getPosition(LLCoordScreen *position) override {return false;}; + bool getSize(LLCoordScreen *size) override {return false;}; + bool getSize(LLCoordWindow *size) override {return false;}; + bool setPosition(LLCoordScreen position) override {return false;}; + bool setSizeImpl(LLCoordScreen size) override {return false;}; + bool switchContext(bool fullscreen, const LLCoordScreen &size, bool disable_vsync, const LLCoordScreen * const posp = NULL) override {return false;}; + bool setCursorPosition(LLCoordWindow position) override {return false;}; + bool getCursorPosition(LLCoordWindow *position) override {return false;}; + bool isWrapMouse() const override { return true; } + void showCursor() override {}; + void hideCursor() override {}; + void showCursorFromMouseMove() override {}; + void hideCursorUntilMouseMove() override {}; + bool isCursorHidden() override {return false;}; + void updateCursor() override {}; + //virtual ECursorType getCursor() override { return mCurrentCursor; }; + void captureMouse() override {}; + void releaseMouse() override {}; + void setMouseClipping( bool b ) override {}; + bool isClipboardTextAvailable() override {return false; }; + bool pasteTextFromClipboard(LLWString &dst) override {return false; }; + bool copyTextToClipboard(const LLWString &src) override {return false; }; + void flashIcon(F32 seconds) override {}; + F32 getGamma() override {return 1.0f; }; + bool setGamma(const F32 gamma) override {return false; }; // Set the gamma + bool restoreGamma() override {return false; }; // Restore original gamma table (before updating gamma) + void setFSAASamples(const U32 fsaa_samples) override { /* FSAA not supported yet on Mesa headless.*/ } + U32 getFSAASamples() override { return 0; } + //virtual ESwapMethod getSwapMethod() override { return mSwapMethod; } + void gatherInput() override {}; + void delayInputProcessing() override {}; + void swapBuffers() override; + + void* createSharedContext()override{return nullptr;}; + void makeContextCurrent(void* context)override{}; + void destroySharedContext(void* context)override{}; + void toggleVSync(bool enable_vsync) override {}; + bool setSizeImpl(LLCoordWindow size) override { return false; }; // handy coordinate space conversion routines - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to) { return false; }; + bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override { return false; }; + bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override { return false; }; + bool convertCoords(LLCoordWindow from, LLCoordGL *to) override { return false; }; + bool convertCoords(LLCoordGL from, LLCoordWindow *to) override { return false; }; + bool convertCoords(LLCoordScreen from, LLCoordGL *to) override { return false; }; + bool convertCoords(LLCoordGL from, LLCoordScreen *to) override { return false; }; - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) { return NULL; }; - /*virtual*/ F32 getNativeAspectRatio() { return 1.0f; }; - /*virtual*/ F32 getPixelAspectRatio() { return 1.0f; }; - /*virtual*/ void setNativeAspectRatio(F32 ratio) {} + LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override { return NULL; }; + F32 getNativeAspectRatio() override { return 1.0f; }; + F32 getPixelAspectRatio() override { return 1.0f; }; + void setNativeAspectRatio(F32 ratio) override {} - /*virtual*/ void *getPlatformWindow() { return 0; }; - /*virtual*/ void bringToFront() {}; + void *getPlatformWindow() override { return 0; }; + void bringToFront() override {}; LLWindowMesaHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, @@ -112,9 +117,9 @@ class LLSplashScreenMesaHeadless : public LLSplashScreen LLSplashScreenMesaHeadless() {}; virtual ~LLSplashScreenMesaHeadless() {}; - /*virtual*/ void showImpl() {}; - /*virtual*/ void updateImpl(const std::string& mesg) {}; - /*virtual*/ void hideImpl() {}; + void showImpl() override {}; + void updateImpl(const std::string& mesg) override {}; + void hideImpl() override {}; }; diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index 05be319c0b3..92b95700db7 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -25,8 +25,6 @@ * $/LicenseInfo$ */ -#if LL_SDL - #include "linden_common.h" #include "llwindowsdl.h" @@ -39,197 +37,76 @@ #include "llstring.h" #include "lldir.h" #include "llfindlocale.h" +#include "llpreeditor.h" -#if LL_GTK -extern "C" { -# include "gtk/gtk.h" -} -#include -#endif // LL_GTK +#ifdef LL_GLIB +#include +#endif +#if LL_LINUX extern "C" { # include "fontconfig/fontconfig.h" } -#if LL_LINUX // not necessarily available on random SDL platforms, so #if LL_LINUX // for execv(), waitpid(), fork() -# include -# include -# include +#include +#include +#include +#include #endif // LL_LINUX +#if LL_DARWIN +#include +#include +#include +#include + +bool LLWindowSDL::sUseMultGL = false; +bool gHiDPISupport = true; +#endif + extern bool gDebugWindowProc; const S32 MAX_NUM_RESOLUTIONS = 200; -// static variable for ATI mouse cursor crash work-around: -static bool ATIbug = false; - // // LLWindowSDL // -#if LL_X11 -# include -#endif //LL_X11 - // TOFU HACK -- (*exactly* the same hack as LLWindowMacOSX for a similar // set of reasons): Stash a pointer to the LLWindowSDL object here and // maintain in the constructor and destructor. This assumes that there will // be only one object of this class at any time. Currently this is true. -static LLWindowSDL *gWindowImplementation = NULL; - - -void maybe_lock_display(void) -{ - if (gWindowImplementation && gWindowImplementation->Lock_Display) { - gWindowImplementation->Lock_Display(); - } -} - - -void maybe_unlock_display(void) -{ - if (gWindowImplementation && gWindowImplementation->Unlock_Display) { - gWindowImplementation->Unlock_Display(); - } -} - - -#if LL_GTK -// Lazily initialize and check the runtime GTK version for goodness. -// static -bool LLWindowSDL::ll_try_gtk_init(void) -{ - static bool done_gtk_diag = false; - static bool gtk_is_good = false; - static bool done_setlocale = false; - static bool tried_gtk_init = false; - - if (!done_setlocale) - { - LL_INFOS() << "Starting GTK Initialization." << LL_ENDL; - maybe_lock_display(); - gtk_disable_setlocale(); - maybe_unlock_display(); - done_setlocale = true; - } - - if (!tried_gtk_init) - { - tried_gtk_init = true; - if (!g_thread_supported ()) g_thread_init (NULL); - maybe_lock_display(); - gtk_is_good = gtk_init_check(NULL, NULL); - maybe_unlock_display(); - if (!gtk_is_good) - LL_WARNS() << "GTK Initialization failed." << LL_ENDL; - } - - if (gtk_is_good && !done_gtk_diag) - { - LL_INFOS() << "GTK Initialized." << LL_ENDL; - LL_INFOS() << "- Compiled against GTK version " - << GTK_MAJOR_VERSION << "." - << GTK_MINOR_VERSION << "." - << GTK_MICRO_VERSION << LL_ENDL; - LL_INFOS() << "- Running against GTK version " - << gtk_major_version << "." - << gtk_minor_version << "." - << gtk_micro_version << LL_ENDL; - maybe_lock_display(); - const gchar* gtk_warning = gtk_check_version( - GTK_MAJOR_VERSION, - GTK_MINOR_VERSION, - GTK_MICRO_VERSION); - maybe_unlock_display(); - if (gtk_warning) - { - LL_WARNS() << "- GTK COMPATIBILITY WARNING: " << - gtk_warning << LL_ENDL; - gtk_is_good = false; - } else { - LL_INFOS() << "- GTK version is good." << LL_ENDL; - } - - done_gtk_diag = true; - } - - return gtk_is_good; -} -#endif // LL_GTK - - -#if LL_X11 -// static -Window LLWindowSDL::get_SDL_XWindowID(void) -{ - if (gWindowImplementation) { - return gWindowImplementation->mSDL_XWindowID; - } - return None; -} - -//static -Display* LLWindowSDL::get_SDL_Display(void) -{ - if (gWindowImplementation) { - return gWindowImplementation->mSDL_Display; - } - return NULL; -} -#endif // LL_X11 - +static LLWindowSDL *gWindowImplementation = nullptr; LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, - const std::string& title, S32 x, S32 y, S32 width, - S32 height, U32 flags, - bool fullscreen, bool clearBg, - bool disable_vsync, bool use_gl, - bool ignore_pixel_depth, U32 fsaa_samples) - : LLWindow(callbacks, fullscreen, flags), - Lock_Display(NULL), - Unlock_Display(NULL), mGamma(1.0f) + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, + S32 height, U32 flags, + bool fullscreen, bool clearBg, + bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples) + : LLWindow(callbacks, fullscreen, flags), + mGamma(1.0f), mFlashing(false) { + SDL_GL_LoadLibrary(nullptr); + // Initialize the keyboard gKeyboard = new LLKeyboardSDL(); gKeyboard->setCallbacks(callbacks); - // Note that we can't set up key-repeat until after SDL has init'd video - - // Ignore use_gl for now, only used for drones on PC - mWindow = NULL; - mNeedsResize = false; - mOverrideAspectRatio = 0.f; - mGrabbyKeyFlags = 0; - mReallyCapturedCount = 0; - mHaveInputFocus = -1; - mIsMinimized = -1; - mFSAASamples = fsaa_samples; - -#if LL_X11 - mSDL_XWindowID = None; - mSDL_Display = NULL; -#endif // LL_X11 - -#if LL_GTK - // We MUST be the first to initialize GTK so that GTK doesn't get badly - // initialized with a non-C locale and cause lots of serious random - // weirdness. - ll_try_gtk_init(); -#endif // LL_GTK // Assume 4:3 aspect ratio until we know better - mOriginalAspectRatio = 1024.0 / 768.0; + mOriginalAspectRatio = 1024.f / 768.f; if (title.empty()) - mWindowTitle = "SDL Window"; // *FIX: (?) + mWindowTitle = "Second Life"; else mWindowTitle = title; // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) + if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) { + gGLManager.initWGL(); gGLManager.initGL(); //start with arrow cursor @@ -241,14 +118,6 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, // Stash an object pointer for OSMessageBox() gWindowImplementation = this; - -#if LL_X11 - mFlashing = false; -#endif // LL_X11 - - mKeyScanCode = 0; - mKeyVirtualKey = 0; - mKeyModifiers = KMOD_NONE; } static SDL_Surface *Load_BMP_Resource(const char *basename) @@ -258,480 +127,287 @@ static SDL_Surface *Load_BMP_Resource(const char *basename) // Figure out where our BMP is living on the disk snprintf(path_buffer, PATH_BUFFER_SIZE-1, "%s%sres-sdl%s%s", - gDirUtilp->getAppRODataDir().c_str(), - gDirUtilp->getDirDelimiter().c_str(), - gDirUtilp->getDirDelimiter().c_str(), - basename); + gDirUtilp->getAppRODataDir().c_str(), + gDirUtilp->getDirDelimiter().c_str(), + gDirUtilp->getDirDelimiter().c_str(), + basename); path_buffer[PATH_BUFFER_SIZE-1] = '\0'; return SDL_LoadBMP(path_buffer); } -#if LL_X11 -// This is an XFree86/XOrg-specific hack for detecting the amount of Video RAM -// on this machine. It works by searching /var/log/var/log/Xorg.?.log or -// /var/log/XFree86.?.log for a ': (VideoRAM ?|Memory): (%d+) kB' regex, where -// '?' is the X11 display number derived from $DISPLAY -static int x11_detect_VRAM_kb_fp(FILE *fp, const char *prefix_str) -{ - const int line_buf_size = 1000; - char line_buf[line_buf_size]; - while (fgets(line_buf, line_buf_size, fp)) - { - //LL_DEBUGS() << "XLOG: " << line_buf << LL_ENDL; - - // Why the ad-hoc parser instead of using a regex? Our - // favourite regex implementation - libboost_regex - is - // quite a heavy and troublesome dependency for the client, so - // it seems a shame to introduce it for such a simple task. - // *FIXME: libboost_regex is a dependency now anyway, so we may - // as well use it instead of this hand-rolled nonsense. - const char *part1_template = prefix_str; - const char part2_template[] = " kB"; - char *part1 = strstr(line_buf, part1_template); - if (part1) // found start of matching line - { - part1 = &part1[strlen(part1_template)]; // -> after - char *part2 = strstr(part1, part2_template); - if (part2) // found end of matching line - { - // now everything between part1 and part2 is - // supposed to be numeric, describing the - // number of kB of Video RAM supported - int rtn = 0; - for (; part1 < part2; ++part1) - { - if (*part1 < '0' || *part1 > '9') - { - // unexpected char, abort parse - rtn = 0; - break; - } - rtn *= 10; - rtn += (*part1) - '0'; - } - if (rtn > 0) - { - // got the kB number. return it now. - return rtn; - } - } - } - } - return 0; // 'could not detect' +void LLWindowSDL::setTitle(const std::string title) +{ + SDL_SetWindowTitle( mWindow, title.c_str() ); } -static int x11_detect_VRAM_kb() +void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) { - std::string x_log_location("/var/log/"); - std::string fname; - int rtn = 0; // 'could not detect' - int display_num = 0; - FILE *fp; - char *display_env = getenv("DISPLAY"); // e.g. :0 or :0.0 or :1.0 etc - // parse DISPLAY number so we can go grab the right log file - if (display_env[0] == ':' && - display_env[1] >= '0' && display_env[1] <= '9') - { - display_num = display_env[1] - '0'; - } - - // *TODO: we could be smarter and see which of Xorg/XFree86 has the - // freshest time-stamp. + LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; - // Try Xorg log first - fname = x_log_location; - fname += "Xorg."; - fname += ('0' + display_num); - fname += ".log"; - fp = fopen(fname.c_str(), "r"); - if (fp) + // If the requested width or height is 0, find the best default for the monitor. + if(width == 0 || height == 0) { - LL_INFOS() << "Looking in " << fname - << " for VRAM info..." << LL_ENDL; - rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); - fclose(fp); - if (0 == rtn) + // Scan through the list of modes, looking for one which has: + // height between 700 and 800 + // aspect ratio closest to the user's original mode + S32 resolutionCount = 0; + LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount); + + if(resolutionList != nullptr) { - fp = fopen(fname.c_str(), "r"); - if (fp) + F32 closestAspect = 0; + U32 closestHeight = 0; + U32 closestWidth = 0; + + LL_INFOS() << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << LL_ENDL; + + for(S32 i=0; i < resolutionCount; i++) { - rtn = x11_detect_VRAM_kb_fp(fp, ": Video RAM: "); - fclose(fp); - if (0 == rtn) + F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight; + + LL_INFOS() << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << LL_ENDL; + + if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) && + (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio))) { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); - fclose(fp); - } + LL_INFOS() << " (new closest mode) " << LL_ENDL; + + // This is the closest mode we've seen yet. + closestWidth = resolutionList[i].mWidth; + closestHeight = resolutionList[i].mHeight; + closestAspect = aspect; } } + + width = closestWidth; + height = closestHeight; } } - else + + if(width == 0 || height == 0) { - LL_INFOS() << "Could not open " << fname - << " - skipped." << LL_ENDL; - // Try old XFree86 log otherwise - fname = x_log_location; - fname += "XFree86."; - fname += ('0' + display_num); - fname += ".log"; - fp = fopen(fname.c_str(), "r"); - if (fp) - { - LL_INFOS() << "Looking in " << fname - << " for VRAM info..." << LL_ENDL; - rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); - fclose(fp); - } - } - } - else - { - LL_INFOS() << "Could not open " << fname - << " - skipped." << LL_ENDL; - } + // Mode search failed for some reason. Use the old-school default. + width = 1024; + height = 768; } - return rtn; } -#endif // LL_X11 -bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool disable_vsync) +bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync) { - //bool glneedsinit = false; - - LL_INFOS() << "createContext, fullscreen=" << fullscreen << - " size=" << width << "x" << height << LL_ENDL; + LL_INFOS() << "createContext, fullscreen=" << fullscreen << " size=" << width << "x" << height << LL_ENDL; // captures don't survive contexts mGrabbyKeyFlags = 0; - mReallyCapturedCount = 0; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) - { - LL_INFOS() << "sdl_init() failed! " << SDL_GetError() << LL_ENDL; - setupFailure("sdl_init() failure, window creation error", "error", OSMB_OK); - return false; - } - - SDL_version c_sdl_version; - SDL_VERSION(&c_sdl_version); - LL_INFOS() << "Compiled against SDL " - << int(c_sdl_version.major) << "." - << int(c_sdl_version.minor) << "." - << int(c_sdl_version.patch) << LL_ENDL; - const SDL_version *r_sdl_version; - r_sdl_version = SDL_Linked_Version(); - LL_INFOS() << " Running against SDL " - << int(r_sdl_version->major) << "." - << int(r_sdl_version->minor) << "." - << int(r_sdl_version->patch) << LL_ENDL; - - const SDL_VideoInfo *video_info = SDL_GetVideoInfo( ); - if (!video_info) - { - LL_INFOS() << "SDL_GetVideoInfo() failed! " << SDL_GetError() << LL_ENDL; - setupFailure("SDL_GetVideoInfo() failed, Window creation error", "Error", OSMB_OK); - return false; - } - if (video_info->current_h > 0) - { - mOriginalAspectRatio = (float)video_info->current_w / (float)video_info->current_h; - LL_INFOS() << "Original aspect ratio was " << video_info->current_w << ":" << video_info->current_h << "=" << mOriginalAspectRatio << LL_ENDL; - } - - SDL_EnableUNICODE(1); - SDL_WM_SetCaption(mWindowTitle.c_str(), mWindowTitle.c_str()); - - // Set the application icon. - SDL_Surface *bmpsurface; - bmpsurface = Load_BMP_Resource("ll_icon.BMP"); - if (bmpsurface) - { - // This attempts to give a black-keyed mask to the icon. - SDL_SetColorKey(bmpsurface, - SDL_SRCCOLORKEY, - SDL_MapRGB(bmpsurface->format, 0,0,0) ); - SDL_WM_SetIcon(bmpsurface, NULL); - // The SDL examples cheerfully avoid freeing the icon - // surface, but I'm betting that's leaky. - SDL_FreeSurface(bmpsurface); - bmpsurface = NULL; - } - - // note: these SetAttributes make Tom's 9600-on-AMD64 fail to - // get a visual, but it's broken anyway when it does, and without - // these SetAttributes we might easily get an avoidable substandard - // visual to work with on most other machines. - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, (bits <= 16) ? 16 : 24); - // We need stencil support for a few (minor) things. - if (!getenv("LL_GL_NO_STENCIL")) - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, (bits <= 16) ? 1 : 8); - - // *FIX: try to toggle vsync here? + if (width == 0) + width = 1024; + if (height == 0) + width = 768; + if (x == 0) + x = SDL_WINDOWPOS_UNDEFINED; + if (y == 0) + y = SDL_WINDOWPOS_UNDEFINED; mFullscreen = fullscreen; - int sdlflags = SDL_OPENGL | SDL_RESIZABLE | SDL_ANYFORMAT; + // Setup default backing colors + GLint redBits{8}, greenBits{8}, blueBits{8}, alphaBits{8}; + GLint depthBits{24}, stencilBits{8}; + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, redBits); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, greenBits); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, blueBits); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, alphaBits); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthBits); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencilBits); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - if (mFSAASamples > 0) + if(LLRender::sGLCoreProfile) { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mFSAASamples); - } +#if LL_DARWIN + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); +#endif - mSDLFlags = sdlflags; + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + } - if (mFullscreen) + SDL_GLContextFlag context_flags{}; + if (gDebugGL) { - LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; - - // If the requested width or height is 0, find the best default for the monitor. - if((width == 0) || (height == 0)) - { - // Scan through the list of modes, looking for one which has: - // height between 700 and 800 - // aspect ratio closest to the user's original mode - S32 resolutionCount = 0; - LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount); - - if(resolutionList != NULL) - { - F32 closestAspect = 0; - U32 closestHeight = 0; - U32 closestWidth = 0; - int i; - - LL_INFOS() << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << LL_ENDL; - - for(i=0; i < resolutionCount; i++) - { - F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight; - - LL_INFOS() << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << LL_ENDL; - - if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) && - (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio))) - { - LL_INFOS() << " (new closest mode) " << LL_ENDL; - - // This is the closest mode we've seen yet. - closestWidth = resolutionList[i].mWidth; - closestHeight = resolutionList[i].mHeight; - closestAspect = aspect; - } - } - - width = closestWidth; - height = closestHeight; - } - } - - if((width == 0) || (height == 0)) - { - // Mode search failed for some reason. Use the old-school default. - width = 1024; - height = 768; - } - - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN); - if (!mWindow && bits > 16) - { - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN); - } - - if (mWindow) - { - mFullscreen = true; - mFullscreenWidth = mWindow->w; - mFullscreenHeight = mWindow->h; - mFullscreenBits = mWindow->format->BitsPerPixel; - mFullscreenRefresh = -1; + context_flags |= SDL_GL_CONTEXT_DEBUG_FLAG; + } - LL_INFOS() << "Running at " << mFullscreenWidth - << "x" << mFullscreenHeight - << "x" << mFullscreenBits - << " @ " << mFullscreenRefresh - << LL_ENDL; - } - else - { - LL_WARNS() << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << LL_ENDL; - // No fullscreen support - mFullscreen = false; - mFullscreenWidth = -1; - mFullscreenHeight = -1; - mFullscreenBits = -1; - mFullscreenRefresh = -1; +#if LL_DARWIN + context_flags |= SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG; +#endif + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, context_flags); + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); + + if(mFullscreen) + { + tryFindFullscreenSize( width, height ); + } + + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, mWindowTitle.c_str()); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, x); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, y); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, width); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, height); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, true); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, mFullscreen); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN, true); +#if LL_DARWIN + //SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, gHiDPISupport); +#endif - std::string error = llformat("Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); - OSMessageBox(error, "Error", OSMB_OK); - } + mWindow = SDL_CreateWindowWithProperties(props); + if (mWindow == nullptr) + { + LL_WARNS() << "Window creation failure. SDL: " << SDL_GetError() << LL_ENDL; + setupFailure("Window creation error", "Error", OSMB_OK); + return false; } + SDL_DestroyProperties(props); // Free properties once window is created - if(!mFullscreen && (mWindow == NULL)) + // Create the context + mContext = SDL_GL_CreateContext(mWindow); + if(!mContext) { - if (width == 0) - width = 1024; - if (height == 0) - width = 768; - - LL_INFOS() << "createContext: creating window " << width << "x" << height << "x" << bits << LL_ENDL; - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); - if (!mWindow && bits > 16) - { - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); - } + LL_WARNS() << "Cannot create GL context " << SDL_GetError() << LL_ENDL; + setupFailure("GL Context creation error", "Error", OSMB_OK); + return false; + } - if (!mWindow) - { - LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL; - setupFailure("Window creation error", "Error", OSMB_OK); - return false; - } - } else if (!mFullscreen && (mWindow != NULL)) + if (!SDL_GL_MakeCurrent(mWindow, mContext)) { - LL_INFOS() << "createContext: SKIPPING - !fullscreen, but +mWindow " << width << "x" << height << "x" << bits << LL_ENDL; + LL_WARNS() << "Failed to make context current. SDL: " << SDL_GetError() << LL_ENDL; + setupFailure("GL Context failed to set current failure", "Error", OSMB_OK); + return false; } - // Detect video memory size. -# if LL_X11 - gGLManager.mVRAM = x11_detect_VRAM_kb() / 1024; - if (gGLManager.mVRAM != 0) - { - LL_INFOS() << "X11 log-parser detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; - } else -# endif // LL_X11 + if(mFullscreen) { - // fallback to letting SDL detect VRAM. - // note: I've not seen SDL's detection ever actually find - // VRAM != 0, but if SDL *does* detect it then that's a bonus. - gGLManager.mVRAM = video_info->video_mem / 1024; - if (gGLManager.mVRAM != 0) + const SDL_DisplayMode* displayMode = SDL_GetCurrentDisplayMode(SDL_GetDisplayForWindow(mWindow)); + if(displayMode) + { + mFullscreenWidth = displayMode->w; + mFullscreenHeight = displayMode->h; + mFullscreenRefresh = ll_round(displayMode->refresh_rate); + + LL_INFOS() << "Running at " << mFullscreenWidth + << "x" << mFullscreenHeight + << " @ " << mFullscreenRefresh + << LL_ENDL; + } + else // Fallback to window size { - LL_INFOS() << "SDL detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; + LL_INFOS() << "Unable to get display mode for current fullscreen display falling back to window size" << LL_ENDL; + SDL_GetWindowSize(mWindow, &mFullscreenWidth, &mFullscreenHeight); + mFullscreenRefresh = -1; } } - // If VRAM is not detected, that is handled later - - // *TODO: Now would be an appropriate time to check for some - // explicitly unsupported cards. - //const char* RENDERER = (const char*) glGetString(GL_RENDERER); - GLint depthBits, stencilBits, redBits, greenBits, blueBits, alphaBits; - - glGetIntegerv(GL_RED_BITS, &redBits); - glGetIntegerv(GL_GREEN_BITS, &greenBits); - glGetIntegerv(GL_BLUE_BITS, &blueBits); - glGetIntegerv(GL_ALPHA_BITS, &alphaBits); - glGetIntegerv(GL_DEPTH_BITS, &depthBits); - glGetIntegerv(GL_STENCIL_BITS, &stencilBits); + SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &redBits); + SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &greenBits); + SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &blueBits); + SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &alphaBits); + SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depthBits); + SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencilBits); LL_INFOS() << "GL buffer:" << LL_ENDL; - LL_INFOS() << " Red Bits " << S32(redBits) << LL_ENDL; - LL_INFOS() << " Green Bits " << S32(greenBits) << LL_ENDL; - LL_INFOS() << " Blue Bits " << S32(blueBits) << LL_ENDL; - LL_INFOS() << " Alpha Bits " << S32(alphaBits) << LL_ENDL; - LL_INFOS() << " Depth Bits " << S32(depthBits) << LL_ENDL; - LL_INFOS() << " Stencil Bits " << S32(stencilBits) << LL_ENDL; + LL_INFOS() << " Red Bits " << S32(redBits) << LL_ENDL; + LL_INFOS() << " Green Bits " << S32(greenBits) << LL_ENDL; + LL_INFOS() << " Blue Bits " << S32(blueBits) << LL_ENDL; + LL_INFOS() << " Alpha Bits " << S32(alphaBits) << LL_ENDL; + LL_INFOS() << " Depth Bits " << S32(depthBits) << LL_ENDL; + LL_INFOS() << " Stencil Bits " << S32(stencilBits) << LL_ENDL; GLint colorBits = redBits + greenBits + blueBits + alphaBits; - // fixme: actually, it's REALLY important for picking that we get at - // least 8 bits each of red,green,blue. Alpha we can be a bit more - // relaxed about if we have to. if (colorBits < 32) { - close(); setupFailure( - "Second Life requires True Color (32-bit) to run in a window.\n" - "Please go to Control Panels -> Display -> Settings and\n" - "set the screen to 32-bit color.\n" - "Alternately, if you choose to run fullscreen, Second Life\n" - "will automatically adjust the screen each time it runs.", - "Error", - OSMB_OK); + "Second Life requires True Color (32-bit) to run in a window.\n" + "Please go to Control Panels -> Display -> Settings and\n" + "set the screen to 32-bit color.\n" + "Alternately, if you choose to run fullscreen, Second Life\n" + "will automatically adjust the screen each time it runs.", + "Error", + OSMB_OK); return false; } -#if 0 // *FIX: we're going to brave it for now... - if (alphaBits < 8) - { - close(); - setupFailure( - "Second Life is unable to run because it can't get an 8 bit alpha\n" - "channel. Usually this is due to video card driver issues.\n" - "Please make sure you have the latest video card drivers installed.\n" - "Also be sure your monitor is set to True Color (32-bit) in\n" - "Control Panels -> Display -> Settings.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); - return false; - } + LL_PROFILER_GPU_CONTEXT; + + // Enable vertical sync + toggleVSync(enable_vsync); + +#if LL_DARWIN + setUseMultGL(sUseMultGL); + + // Get vram via CGL on macos + gGLManager.mVRAM = getVramSize(); #endif -#if LL_X11 - /* Grab the window manager specific information */ - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - if ( SDL_GetWMInfo(&info) ) + // Set the application icon. + SDL_Surface* bmpsurface = Load_BMP_Resource("ll_icon.BMP"); + if (bmpsurface) { - /* Save the information for later use */ - if ( info.subsystem == SDL_SYSWM_X11 ) - { - mSDL_Display = info.info.x11.display; - mSDL_XWindowID = info.info.x11.wmwindow; - Lock_Display = info.info.x11.lock_func; - Unlock_Display = info.info.x11.unlock_func; - } - else - { - LL_WARNS() << "We're not running under X11? Wild." - << LL_ENDL; - } + SDL_SetWindowIcon(mWindow, bmpsurface); + SDL_DestroySurface(bmpsurface); + bmpsurface = nullptr; } - else + + SDL_StartTextInput(mWindow); + return true; +} + +void* LLWindowSDL::createSharedContext() +{ + SDL_GLContext pContext = SDL_GL_CreateContext(mWindow); + if (pContext) { - LL_WARNS() << "We're not running under any known WM. Wild." - << LL_ENDL; + // HACK to ensure windows GL context is set correctly when threaded - Rye + SDL_GL_MakeCurrent(mWindow, pContext); + SDL_GL_MakeCurrent(mWindow, mContext); + LL_DEBUGS() << "Creating shared OpenGL context successful!" << LL_ENDL; + return (void*)pContext; } -#endif // LL_X11 - - //make sure multisampling is disabled by default - glDisable(GL_MULTISAMPLE_ARB); + LL_WARNS() << "Creating shared OpenGL context failed!" << LL_ENDL; + return nullptr; +} - // We need to do this here, once video is init'd - if (-1 == SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, - SDL_DEFAULT_REPEAT_INTERVAL)) - LL_WARNS() << "Couldn't enable key-repeat: " << SDL_GetError() <mX = 0; - position->mY = 0; - return true; + if (mWindow) + { + SDL_GetWindowPosition(mWindow, &position->mX, &position->mY); + return true; + } + return false; } bool LLWindowSDL::getSize(LLCoordScreen *size) { if (mWindow) { - size->mX = mWindow->w; - size->mY = mWindow->h; - return (true); + SDL_GetWindowSize(mWindow, &size->mX, &size->mY); + return true; } - return (false); + return false; } bool LLWindowSDL::getSize(LLCoordWindow *size) { if (mWindow) { - size->mX = mWindow->w; - size->mY = mWindow->h; - return (true); + SDL_GetWindowSize(mWindow, &size->mX, &size->mY); + return true; } - return (false); + return false; } bool LLWindowSDL::setPosition(const LLCoordScreen position) { - if(mWindow) + if (mWindow) { - // *FIX: (?) - //MacMoveWindow(mWindow, position.mX, position.mY, false); + SDL_SetWindowPosition(mWindow, position.mX, position.mY); + return true; } - return true; + return false; } -bool LLWindowSDL::setSizeImpl(const LLCoordScreen size) +template< typename T > bool setSizeImpl( const T& newSize, SDL_Window *pWin ) { - if(mWindow) - { - // Push a resize event onto SDL's queue - we'll handle it - // when it comes out again. - SDL_Event event; - event.type = SDL_VIDEORESIZE; - event.resize.w = size.mX; - event.resize.h = size.mY; - SDL_PushEvent(&event); // copied into queue + if( !pWin ) + return false; - return true; - } + SDL_WindowFlags winFlags = SDL_GetWindowFlags( pWin ); - return false; + if( winFlags & SDL_WINDOW_MAXIMIZED ) + SDL_RestoreWindow( pWin ); + + SDL_SetWindowSize( pWin, newSize.mX, newSize.mY ); + return true; } -bool LLWindowSDL::setSizeImpl(const LLCoordWindow size) +bool LLWindowSDL::setSizeImpl(const LLCoordScreen size) { - if(mWindow) - { - // Push a resize event onto SDL's queue - we'll handle it - // when it comes out again. - SDL_Event event; - event.type = SDL_VIDEORESIZE; - event.resize.w = size.mX; - event.resize.h = size.mY; - SDL_PushEvent(&event); // copied into queue - - return true; - } + return ::setSizeImpl( size, mWindow ); +} - return false; +bool LLWindowSDL::setSizeImpl(const LLCoordWindow size) +{ + return ::setSizeImpl( size, mWindow ); } @@ -968,8 +656,9 @@ void LLWindowSDL::swapBuffers() { if (mWindow) { - SDL_GL_SwapBuffers(); + SDL_GL_SwapWindow(mWindow); } + LL_PROFILER_GPU_COLLECT; } U32 LLWindowSDL::getFSAASamples() @@ -984,22 +673,23 @@ void LLWindowSDL::setFSAASamples(const U32 samples) F32 LLWindowSDL::getGamma() { - return 1/mGamma; + return 1.f / mGamma; } bool LLWindowSDL::restoreGamma() { - //CGDisplayRestoreColorSyncSettings(); - SDL_SetGamma(1.0f, 1.0f, 1.0f); return true; } bool LLWindowSDL::setGamma(const F32 gamma) { - mGamma = gamma; - if (mGamma == 0) mGamma = 0.1f; - mGamma = 1/mGamma; - SDL_SetGamma(mGamma, mGamma, mGamma); + if (mWindow) + { + mGamma = gamma; + if (mGamma == 0) + mGamma = 0.1f; + mGamma = 1.f / mGamma; + } return true; } @@ -1008,12 +698,11 @@ bool LLWindowSDL::isCursorHidden() return mCursorHidden; } - - // Constrains the mouse to the window. -void LLWindowSDL::setMouseClipping( bool b ) +void LLWindowSDL::setMouseClipping(bool b) { - //SDL_WM_GrabInput(b ? SDL_GRAB_ON : SDL_GRAB_OFF); + if( mWindow ) + SDL_SetWindowMouseGrab(mWindow, b); } // virtual @@ -1021,38 +710,16 @@ void LLWindowSDL::setMinSize(U32 min_width, U32 min_height, bool enforce_immedia { LLWindow::setMinSize(min_width, min_height, enforce_immediately); -#if LL_X11 - // Set the minimum size limits for X11 window - // so the window manager doesn't allow resizing below those limits. - XSizeHints* hints = XAllocSizeHints(); - hints->flags |= PMinSize; - hints->min_width = mMinWindowWidth; - hints->min_height = mMinWindowHeight; - - XSetWMNormalHints(mSDL_Display, mSDL_XWindowID, hints); - - XFree(hints); -#endif + if (mWindow && min_width > 0 && min_height > 0) + { + SDL_SetWindowMinimumSize(mWindow, mMinWindowWidth, mMinWindowHeight); + } } bool LLWindowSDL::setCursorPosition(const LLCoordWindow position) { - bool result = true; - LLCoordScreen screen_pos; - - if (!convertCoords(position, &screen_pos)) - { - return false; - } - - //LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; - - // do the actual forced cursor move. - SDL_WarpMouse(screen_pos.mX, screen_pos.mY); - - //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; - - return result; + SDL_WarpMouseInWindow(mWindow, (F32)position.mX, (F32)position.mY); + return true; } bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) @@ -1060,48 +727,17 @@ bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) //Point cursor_point; LLCoordScreen screen_pos; - //GetMouse(&cursor_point); - int x, y; + float x, y; SDL_GetMouseState(&x, &y); - screen_pos.mX = x; - screen_pos.mY = y; + screen_pos.mX = (S32)x; + screen_pos.mY = (S32)y; return convertCoords(screen_pos, position); } - F32 LLWindowSDL::getNativeAspectRatio() { -#if 0 - // RN: this hack presumes that the largest supported resolution is monitor-limited - // and that pixels in that mode are square, therefore defining the native aspect ratio - // of the monitor...this seems to work to a close approximation for most CRTs/LCDs - S32 num_resolutions; - LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); - - - return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); - //rn: AC -#endif - - // MBW -- there are a couple of bad assumptions here. One is that the display list won't include - // ridiculous resolutions nobody would ever use. The other is that the list is in order. - - // New assumptions: - // - pixels are square (the only reasonable choice, really) - // - The user runs their display at a native resolution, so the resolution of the display - // when the app is launched has an aspect ratio that matches the monitor. - - //RN: actually, the assumption that there are no ridiculous resolutions (above the display's native capabilities) has - // been born out in my experience. - // Pixels are often not square (just ask the people who run their LCDs at 1024x768 or 800x600 when running fullscreen, like me) - // The ordering of display list is a blind assumption though, so we should check for max values - // Things might be different on the Mac though, so I'll defer to MBW - - // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution - // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. - if (mOverrideAspectRatio > 0.f) { return mOverrideAspectRatio; @@ -1130,104 +766,26 @@ F32 LLWindowSDL::getPixelAspectRatio() // dialogs are still usable in fullscreen. void LLWindowSDL::beforeDialog() { - bool running_x11 = false; -#if LL_X11 - running_x11 = (mSDL_XWindowID != None); -#endif //LL_X11 - LL_INFOS() << "LLWindowSDL::beforeDialog()" << LL_ENDL; if (SDLReallyCaptureInput(false)) // must ungrab input so popup works! { - if (mFullscreen) - { - // need to temporarily go non-fullscreen; bless SDL - // for providing a SDL_WM_ToggleFullScreen() - though - // it only works in X11 - if (running_x11 && mWindow) - { - SDL_WM_ToggleFullScreen(mWindow); - } - } - } - -#if LL_X11 - if (mSDL_Display) - { - // Everything that we/SDL asked for should happen before we - // potentially hand control over to GTK. - maybe_lock_display(); - XSync(mSDL_Display, False); - maybe_unlock_display(); + if (mFullscreen && mWindow ) + SDL_SetWindowFullscreen( mWindow, 0 ); } -#endif // LL_X11 - -#if LL_GTK - // this is a good time to grab some GTK version information for - // diagnostics, if not already done. - ll_try_gtk_init(); -#endif // LL_GTK - - maybe_lock_display(); } void LLWindowSDL::afterDialog() { - bool running_x11 = false; -#if LL_X11 - running_x11 = (mSDL_XWindowID != None); -#endif //LL_X11 - LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; - maybe_unlock_display(); - - if (mFullscreen) - { - // need to restore fullscreen mode after dialog - only works - // in X11 - if (running_x11 && mWindow) - { - SDL_WM_ToggleFullScreen(mWindow); - } - } + if (mFullscreen && mWindow ) + SDL_SetWindowFullscreen( mWindow, 0 ); } - -#if LL_X11 -// set/reset the XWMHints flag for 'urgency' that usually makes the icon flash -void LLWindowSDL::x11_set_urgent(bool urgent) -{ - if (mSDL_Display && !mFullscreen) - { - XWMHints *wm_hints; - - LL_INFOS() << "X11 hint for urgency, " << urgent << LL_ENDL; - - maybe_lock_display(); - wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); - if (!wm_hints) - wm_hints = XAllocWMHints(); - - if (urgent) - wm_hints->flags |= XUrgencyHint; - else - wm_hints->flags &= ~XUrgencyHint; - - XSetWMHints(mSDL_Display, mSDL_XWindowID, wm_hints); - XFree(wm_hints); - XSync(mSDL_Display, False); - maybe_unlock_display(); - } -} -#endif // LL_X11 - void LLWindowSDL::flashIcon(F32 seconds) { -#if !LL_X11 - LL_INFOS() << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; -#else - LL_INFOS() << "X11 LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; + LL_INFOS() << "LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; F32 remaining_time = mFlashTimer.getRemainingTimeF32(); if (remaining_time < seconds) @@ -1235,132 +793,71 @@ void LLWindowSDL::flashIcon(F32 seconds) mFlashTimer.reset(); mFlashTimer.setTimerExpirySec(remaining_time); - x11_set_urgent(true); + SDL_FlashWindow(mWindow, SDL_FLASH_UNTIL_FOCUSED); mFlashing = true; -#endif // LL_X11 } - -#if LL_GTK -bool LLWindowSDL::isClipboardTextAvailable() +void LLWindowSDL::maybeStopFlashIcon() { - if (ll_try_gtk_init()) + if (mFlashing && mFlashTimer.hasExpired()) { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_NONE); - return gtk_clipboard_wait_is_text_available(clipboard) ? - true : false; + mFlashing = false; + SDL_FlashWindow( mWindow, SDL_FLASH_CANCEL ); } - return false; // failure } -bool LLWindowSDL::pasteTextFromClipboard(LLWString &text) +bool LLWindowSDL::isClipboardTextAvailable() { - if (ll_try_gtk_init()) + return SDL_HasClipboardText(); +} + +bool LLWindowSDL::pasteTextFromClipboard(LLWString &dst) +{ + if (isClipboardTextAvailable()) { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_NONE); - gchar * const data = gtk_clipboard_wait_for_text(clipboard); + char* data = SDL_GetClipboardText(); if (data) { - text = LLWString(utf8str_to_wstring(data)); - g_free(data); + dst = LLWString(utf8str_to_wstring(data)); + SDL_free(data); return true; } } - return false; // failure + return false; } -bool LLWindowSDL::copyTextToClipboard(const LLWString &text) +bool LLWindowSDL::copyTextToClipboard(const LLWString& text) { - if (ll_try_gtk_init()) - { - const std::string utf8 = wstring_to_utf8str(text); - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_NONE); - gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); - return true; - } - return false; // failure + const std::string utf8 = wstring_to_utf8str(text); + return SDL_SetClipboardText(utf8.c_str()); } - bool LLWindowSDL::isPrimaryTextAvailable() { - if (ll_try_gtk_init()) - { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_SELECTION_PRIMARY); - return gtk_clipboard_wait_is_text_available(clipboard) ? - true : false; - } - return false; // failure + return SDL_HasPrimarySelectionText(); } -bool LLWindowSDL::pasteTextFromPrimary(LLWString &text) +bool LLWindowSDL::pasteTextFromPrimary(LLWString &dst) { - if (ll_try_gtk_init()) + if (isPrimaryTextAvailable()) { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_SELECTION_PRIMARY); - gchar * const data = gtk_clipboard_wait_for_text(clipboard); + char* data = SDL_GetPrimarySelectionText(); if (data) { - text = LLWString(utf8str_to_wstring(data)); - g_free(data); + dst = LLWString(utf8str_to_wstring(data)); + SDL_free(data); return true; } } - return false; // failure -} - -bool LLWindowSDL::copyTextToPrimary(const LLWString &text) -{ - if (ll_try_gtk_init()) - { - const std::string utf8 = wstring_to_utf8str(text); - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_SELECTION_PRIMARY); - gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); - return true; - } - return false; // failure -} - -#else - -bool LLWindowSDL::isClipboardTextAvailable() -{ - return false; // unsupported -} - -bool LLWindowSDL::pasteTextFromClipboard(LLWString &dst) -{ - return false; // unsupported -} - -bool LLWindowSDL::copyTextToClipboard(const LLWString &s) -{ - return false; // unsupported -} - -bool LLWindowSDL::isPrimaryTextAvailable() -{ - return false; // unsupported -} - -bool LLWindowSDL::pasteTextFromPrimary(LLWString &dst) -{ - return false; // unsupported + return false; } -bool LLWindowSDL::copyTextToPrimary(const LLWString &s) +bool LLWindowSDL::copyTextToPrimary(const LLWString& text) { - return false; // unsupported + const std::string utf8 = wstring_to_utf8str(text); + return SDL_SetPrimarySelectionText(utf8.c_str()); } -#endif // LL_GTK - LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions) { if (!mSupportedResolutions) @@ -1368,28 +865,21 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; mNumSupportedResolutions = 0; - SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN); - if ( (modes != NULL) && (modes != ((SDL_Rect **) -1)) ) - { - int count = 0; - while (*modes && countw; - int h = r->h; + SDL_DisplayID display = SDL_GetPrimaryDisplay(); + int num_modes = 0; + SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(display, &num_modes); + num_modes = llclamp(num_modes, 0, MAX_NUM_RESOLUTIONS); + if (modes) { + for (int i = 0; i < num_modes; ++i) { + SDL_DisplayMode *mode = modes[i]; + int w = mode->w; + int h = mode->h; if ((w >= 800) && (h >= 600)) { // make sure we don't add the same resolution multiple times! if ( (mNumSupportedResolutions == 0) || - ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) && - (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) ) + ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) && + (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) ) { mSupportedResolutions[mNumSupportedResolutions].mWidth = w; mSupportedResolutions[mNumSupportedResolutions].mHeight = h; @@ -1397,6 +887,7 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso } } } + SDL_free(modes); } } @@ -1404,13 +895,39 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso return mSupportedResolutions; } +//static +std::vector LLWindowSDL::getDisplaysResolutionList() +{ + std::vector ret; + if (gWindowImplementation) + { + S32 resolutionCount = 0; + LLWindowResolution* resolutionList = gWindowImplementation->getSupportedResolutions(resolutionCount); + if (resolutionList != nullptr) + { + for (S32 i = 0; i < resolutionCount; i++) + { + const LLWindowResolution& resolution = resolutionList[i]; + ret.push_back(std::to_string(resolution.mWidth) + "x" + std::to_string(resolution.mHeight)); + } + } + } + return ret; +} + + bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to) { if (!to) return false; + if (!mWindow) + return false; + S32 height; + SDL_GetWindowSize(mWindow, nullptr, &height); + to->mX = from.mX; - to->mY = mWindow->h - from.mY - 1; + to->mY = height - from.mY - 1; return true; } @@ -1420,8 +937,13 @@ bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) if (!to) return false; + if (!mWindow) + return false; + S32 height; + SDL_GetWindowSize(mWindow, nullptr, &height); + to->mX = from.mX; - to->mY = mWindow->h - from.mY - 1; + to->mY = height - from.mY - 1; return true; } @@ -1434,7 +956,7 @@ bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) // In the fullscreen case, window and screen coordinates are the same. to->mX = from.mX; to->mY = from.mY; - return (true); + return true; } bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) @@ -1445,116 +967,41 @@ bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) // In the fullscreen case, window and screen coordinates are the same. to->mX = from.mX; to->mY = from.mY; - return (true); + return true; } bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) { LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return convertCoords(from, &window_coord) && convertCoords(window_coord, to); } bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to) { LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return convertCoords(from, &window_coord) && convertCoords(window_coord, to); } - - - void LLWindowSDL::setupFailure(const std::string& text, const std::string& caption, U32 type) { - destroyContext(); + close(); OSMessageBox(text, caption, type); } bool LLWindowSDL::SDLReallyCaptureInput(bool capture) { - // note: this used to be safe to call nestedly, but in the - // end that's not really a wise usage pattern, so don't. - - if (capture) - mReallyCapturedCount = 1; - else - mReallyCapturedCount = 0; - - SDL_GrabMode wantmode, newmode; - if (mReallyCapturedCount <= 0) // uncapture + if (!mFullscreen && mWindow ) /* only bother if we're windowed anyway */ { - wantmode = SDL_GRAB_OFF; - } else // capture - { - wantmode = SDL_GRAB_ON; - } - - if (mReallyCapturedCount < 0) // yuck, imbalance. - { - mReallyCapturedCount = 0; - LL_WARNS() << "ReallyCapture count was < 0" << LL_ENDL; + SDL_SetWindowMouseGrab(mWindow, capture); } - if (!mFullscreen) /* only bother if we're windowed anyway */ - { -#if LL_X11 - if (mSDL_Display) - { - /* we dirtily mix raw X11 with SDL so that our pointer - isn't (as often) constrained to the limits of the - window while grabbed, which feels nicer and - hopefully eliminates some reported 'sticky pointer' - problems. We use raw X11 instead of - SDL_WM_GrabInput() because the latter constrains - the pointer to the window and also steals all - *keyboard* input from the window manager, which was - frustrating users. */ - int result; - if (wantmode == SDL_GRAB_ON) - { - //LL_INFOS() << "X11 POINTER GRABBY" << LL_ENDL; - //newmode = SDL_WM_GrabInput(wantmode); - maybe_lock_display(); - result = XGrabPointer(mSDL_Display, mSDL_XWindowID, - True, 0, GrabModeAsync, - GrabModeAsync, - None, None, CurrentTime); - maybe_unlock_display(); - if (GrabSuccess == result) - newmode = SDL_GRAB_ON; - else - newmode = SDL_GRAB_OFF; - } else if (wantmode == SDL_GRAB_OFF) - { - //LL_INFOS() << "X11 POINTER UNGRABBY" << LL_ENDL; - newmode = SDL_GRAB_OFF; - //newmode = SDL_WM_GrabInput(SDL_GRAB_OFF); - - maybe_lock_display(); - XUngrabPointer(mSDL_Display, CurrentTime); - // Make sure the ungrab happens RIGHT NOW. - XSync(mSDL_Display, False); - maybe_unlock_display(); - } else - { - newmode = SDL_GRAB_QUERY; // neutral - } - } else // not actually running on X11, for some reason - newmode = wantmode; -#endif // LL_X11 - } else { - // pretend we got what we wanted, when really we don't care. - newmode = wantmode; - } - - // return boolean success for whether we ended up in the desired state - return (capture && SDL_GRAB_ON==newmode) || - (!capture && SDL_GRAB_OFF==newmode); + return capture; } -U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, bool gain) +U32 LLWindowSDL::SDLCheckGrabbyKeys(U32 keysym, bool gain) { /* part of the fix for SL-13243: Some popular window managers like to totally eat alt-drag for the purposes of moving windows. We @@ -1572,16 +1019,16 @@ U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, bool gain) U32 mask = 0; switch (keysym) { - case SDLK_LALT: - mask = 1U << 0; break; - case SDLK_RALT: - mask = 1U << 1; break; - case SDLK_LCTRL: - mask = 1U << 2; break; - case SDLK_RCTRL: - mask = 1U << 3; break; - default: - break; + case SDLK_LALT: + mask = 1U << 0; break; + case SDLK_RALT: + mask = 1U << 1; break; + case SDLK_LCTRL: + mask = 1U << 2; break; + case SDLK_RCTRL: + mask = 1U << 3; break; + default: + break; } if (gain) @@ -1613,7 +1060,7 @@ void check_vm_bloat() ssize_t res; size_t dummy; - char *ptr = NULL; + char *ptr = nullptr; for (int i=0; i<22; ++i) // parse past the values we don't want { res = getdelim(&ptr, &dummy, ' ', fp); @@ -1623,7 +1070,7 @@ void check_vm_bloat() goto finally; } free(ptr); - ptr = NULL; + ptr = nullptr; } // 23rd space-delimited entry is vsize res = getdelim(&ptr, &dummy, ' ', fp); @@ -1635,7 +1082,7 @@ void check_vm_bloat() } this_vm_size = atoll(ptr); free(ptr); - ptr = NULL; + ptr = nullptr; // 24th space-delimited entry is RSS res = getdelim(&ptr, &dummy, ' ', fp); llassert(ptr); @@ -1646,12 +1093,11 @@ void check_vm_bloat() } this_rss_size = getpagesize() * atoll(ptr); free(ptr); - ptr = NULL; + ptr = nullptr; LL_INFOS() << "VM SIZE IS NOW " << (this_vm_size/(1024*1024)) << " MB, RSS SIZE IS NOW " << (this_rss_size/(1024*1024)) << " MB" << LL_ENDL; - if (llabs(last_vm_size - this_vm_size) > - significant_vm_difference) + if (llabs(last_vm_size - this_vm_size) > significant_vm_difference) { if (this_vm_size > last_vm_size) { @@ -1663,8 +1109,7 @@ void check_vm_bloat() } } - if (llabs(last_rss_size - this_rss_size) > - significant_rss_difference) + if (llabs(last_rss_size - this_rss_size) > significant_rss_difference) { if (this_rss_size > last_rss_size) { @@ -1680,10 +1125,10 @@ void check_vm_bloat() last_vm_size = this_vm_size; finally: - if (NULL != ptr) + if (ptr) { free(ptr); - ptr = NULL; + ptr = nullptr; } fclose(fp); } @@ -1694,33 +1139,17 @@ void check_vm_bloat() // virtual void LLWindowSDL::processMiscNativeEvents() { -#if LL_GTK - // Pump GTK events to avoid starvation for: - // * DBUS servicing - // * Anything else which quietly hooks into the default glib/GTK loop - if (ll_try_gtk_init()) - { - // Yuck, Mozilla's GTK callbacks play with the locale - push/pop - // the locale to protect it, as exotic/non-C locales - // causes our code lots of general critical weirdness - // and crashness. (SL-35450) - static std::string saved_locale; - saved_locale = ll_safe_string(setlocale(LC_ALL, NULL)); - - // Pump until we've nothing left to do or passed 1/15th of a - // second pumping for this frame. - static LLTimer pump_timer; - pump_timer.reset(); - pump_timer.setTimerExpirySec(1.0f / 15.0f); - do { - // Always do at least one non-blocking pump - gtk_main_iteration_do(false); - } while (gtk_events_pending() && - !pump_timer.hasExpired()); - - setlocale(LC_ALL, saved_locale.c_str() ); - } -#endif // LL_GTK +#if LL_GLIB + // Pump until we've nothing left to do or passed 1/15th of a + // second pumping for this frame. + static LLTimer pump_timer; + pump_timer.reset(); + pump_timer.setTimerExpirySec(1.0f / 15.0f); + do + { + g_main_context_iteration(g_main_context_default(), false); + } while( g_main_context_pending(g_main_context_default()) && !pump_timer.hasExpired()); +#endif // hack - doesn't belong here - but this is just for debugging if (getenv("LL_DEBUG_BLOAT")) @@ -1731,235 +1160,243 @@ void LLWindowSDL::processMiscNativeEvents() void LLWindowSDL::gatherInput() { - const Uint32 CLICK_THRESHOLD = 300; // milliseconds - static int leftClick = 0; - static int rightClick = 0; - static Uint32 lastLeftDown = 0; - static Uint32 lastRightDown = 0; SDL_Event event; // Handle all outstanding SDL events while (SDL_PollEvent(&event)) { - switch (event.type) + handleEvent(event); + } + + updateCursor(); + + // This is a good time to stop flashing the icon if our mFlashTimer has + // expired. + if (mFlashing && mFlashTimer.hasExpired()) + { + SDL_FlashWindow(mWindow, SDL_FLASH_CANCEL); + mFlashing = false; + } +} + +SDL_AppResult LLWindowSDL::handleEvent(const SDL_Event& event) +{ + switch(event.type) + { + case SDL_EVENT_MOUSE_MOTION: + { + LLCoordWindow winCoord((S32)event.motion.x, (S32)event.motion.y); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + mCallbacks->handleMouseMove(this, openGlCoord, gKeyboard->currentMask(true)); + break; + } + + case SDL_EVENT_MOUSE_WHEEL: { - case SDL_MOUSEMOTION: + if( event.wheel.y != 0 ) { - LLCoordWindow winCoord(event.button.x, event.button.y); - LLCoordGL openGlCoord; - convertCoords(winCoord, &openGlCoord); - MASK mask = gKeyboard->currentMask(true); - mCallbacks->handleMouseMove(this, openGlCoord, mask); - break; + mCallbacks->handleScrollWheel(this, -event.wheel.y); } - - case SDL_KEYDOWN: - mKeyScanCode = event.key.keysym.scancode; - mKeyVirtualKey = event.key.keysym.unicode; - mKeyModifiers = event.key.keysym.mod; - - gKeyboard->handleKeyDown(event.key.keysym.sym, event.key.keysym.mod); - // part of the fix for SL-13243 - if (SDLCheckGrabbyKeys(event.key.keysym.sym, true) != 0) - SDLReallyCaptureInput(true); - - if (event.key.keysym.unicode) + if (event.wheel.x != 0) { - handleUnicodeUTF16(event.key.keysym.unicode, - gKeyboard->currentMask(false)); + mCallbacks->handleScrollHWheel(this, -event.wheel.x); } - break; + break; + } - case SDL_KEYUP: - mKeyScanCode = event.key.keysym.scancode; - mKeyVirtualKey = event.key.keysym.unicode; - mKeyModifiers = event.key.keysym.mod; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + { + LLCoordWindow winCoord(S32(event.button.x), S32(event.button.y)); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + MASK mask = gKeyboard->currentMask(true); - if (SDLCheckGrabbyKeys(event.key.keysym.sym, false) == 0) - SDLReallyCaptureInput(false); // part of the fix for SL-13243 + if (event.button.button == SDL_BUTTON_LEFT) // left + { + if (event.button.clicks == 2) + mCallbacks->handleDoubleClick(this, openGlCoord, mask); + else + mCallbacks->handleMouseDown(this, openGlCoord, mask); + } + else if (event.button.button == SDL_BUTTON_RIGHT) + { + mCallbacks->handleRightMouseDown(this, openGlCoord, mask); + } + else if (event.button.button == SDL_BUTTON_MIDDLE) // middle + { + mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); + } + else + { + mCallbacks->handleOtherMouseDown(this, openGlCoord, mask, event.button.button); + } - gKeyboard->handleKeyUp(event.key.keysym.sym, event.key.keysym.mod); break; + } + + case SDL_EVENT_MOUSE_BUTTON_UP: + { + LLCoordWindow winCoord(S32(event.button.x), S32(event.button.y)); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + MASK mask = gKeyboard->currentMask(true); - case SDL_MOUSEBUTTONDOWN: + if (event.button.button == SDL_BUTTON_LEFT) // left { - bool isDoubleClick = false; - LLCoordWindow winCoord(event.button.x, event.button.y); - LLCoordGL openGlCoord; - convertCoords(winCoord, &openGlCoord); - MASK mask = gKeyboard->currentMask(true); + mCallbacks->handleMouseUp(this, openGlCoord, mask); + } + else if (event.button.button == SDL_BUTTON_RIGHT) // right + { + mCallbacks->handleRightMouseUp(this, openGlCoord, mask); + } + else if (event.button.button == SDL_BUTTON_MIDDLE) // middle + { + mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask); + } + else + { + mCallbacks->handleOtherMouseUp(this, openGlCoord, mask, event.button.button); + } - if (event.button.button == SDL_BUTTON_LEFT) // SDL doesn't manage double clicking... - { - Uint32 now = SDL_GetTicks(); - if ((now - lastLeftDown) > CLICK_THRESHOLD) - leftClick = 1; - else - { - if (++leftClick >= 2) - { - leftClick = 0; - isDoubleClick = true; - } - } - lastLeftDown = now; - } - else if (event.button.button == SDL_BUTTON_RIGHT) - { - Uint32 now = SDL_GetTicks(); - if ((now - lastRightDown) > CLICK_THRESHOLD) - rightClick = 1; - else - { - if (++rightClick >= 2) - { - rightClick = 0; - isDoubleClick = true; - } - } - lastRightDown = now; - } + break; + } - if (event.button.button == SDL_BUTTON_LEFT) // left - { - if (isDoubleClick) - mCallbacks->handleDoubleClick(this, openGlCoord, mask); - else - mCallbacks->handleMouseDown(this, openGlCoord, mask); - } + case SDL_EVENT_KEY_DOWN: + { + mKeyVirtualKey = event.key.key; + mKeyModifiers = event.key.mod; - else if (event.button.button == SDL_BUTTON_RIGHT) // right - { - mCallbacks->handleRightMouseDown(this, openGlCoord, mask); - } + if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) + { + mKeyVirtualKey = SDLK_RETURN; + } - else if (event.button.button == SDL_BUTTON_MIDDLE) // middle - { - mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); - } - else if (event.button.button == 4) // mousewheel up...thanks to X11 for making SDL consider these "buttons". - mCallbacks->handleScrollWheel(this, -1); - else if (event.button.button == 5) // mousewheel down...thanks to X11 for making SDL consider these "buttons". - mCallbacks->handleScrollWheel(this, 1); + gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers); - break; - } + if (mKeyVirtualKey == SDLK_RETURN) + mCallbacks->handleUnicodeChar(mKeyVirtualKey, gKeyboard->currentMask(false)); - case SDL_MOUSEBUTTONUP: - { - LLCoordWindow winCoord(event.button.x, event.button.y); - LLCoordGL openGlCoord; - convertCoords(winCoord, &openGlCoord); - MASK mask = gKeyboard->currentMask(true); - - if (event.button.button == SDL_BUTTON_LEFT) // left - mCallbacks->handleMouseUp(this, openGlCoord, mask); - else if (event.button.button == SDL_BUTTON_RIGHT) // right - mCallbacks->handleRightMouseUp(this, openGlCoord, mask); - else if (event.button.button == SDL_BUTTON_MIDDLE) // middle - mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask); - // don't handle mousewheel here... - - break; - } + // part of the fix for SL-13243 + if (SDLCheckGrabbyKeys(mKeyVirtualKey, true) != 0) + SDLReallyCaptureInput(true); + break; + } - case SDL_VIDEOEXPOSE: // VIDEOEXPOSE doesn't specify the damage, but hey, it's OpenGL...repaint the whole thing! - mCallbacks->handlePaint(this, 0, 0, mWindow->w, mWindow->h); - break; + case SDL_EVENT_KEY_UP: + { + mKeyVirtualKey = event.key.key; + mKeyModifiers = event.key.mod; - case SDL_VIDEORESIZE: // *FIX: handle this? + if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) { - LL_INFOS() << "Handling a resize event: " << event.resize.w << - "x" << event.resize.h << LL_ENDL; + mKeyVirtualKey = SDLK_RETURN; + } - S32 width = llmax(event.resize.w, (S32)mMinWindowWidth); - S32 height = llmax(event.resize.h, (S32)mMinWindowHeight); + if (SDLCheckGrabbyKeys(mKeyVirtualKey, false) == 0) + SDLReallyCaptureInput(false); // part of the fix for SL-13243 - // *FIX: I'm not sure this is necessary! - mWindow = SDL_SetVideoMode(width, height, 32, mSDLFlags); - if (!mWindow) - { - // *FIX: More informative dialog? - LL_INFOS() << "Could not recreate context after resize! Quitting..." << LL_ENDL; - if(mCallbacks->handleCloseRequest(this, false)) - { - // Get the app to initiate cleanup. - mCallbacks->handleQuit(this); - // The app is responsible for calling destroyWindow when done with GL - } - break; + gKeyboard->handleKeyUp(mKeyVirtualKey, mKeyModifiers); + break; } - mCallbacks->handleResize(this, width, height); - break; - } - case SDL_ACTIVEEVENT: - if (event.active.state & SDL_APPINPUTFOCUS) - { - // Note that for SDL (particularly on X11), keyboard - // and mouse focus are independent things. Here we are - // tracking keyboard focus state changes. - - // We have to do our own state massaging because SDL - // can send us two unfocus events in a row for example, - // which confuses the focus code [SL-24071]. - if (event.active.gain != mHaveInputFocus) + case SDL_EVENT_TEXT_INPUT: + { + auto string = utf8str_to_wstring(event.text.text); + mKeyModifiers = gKeyboard->currentMask( false ); + for (auto key : string) { - mHaveInputFocus = !!event.active.gain; - - if (mHaveInputFocus) - mCallbacks->handleFocus(this); + mKeyVirtualKey = key; + if (mKeyModifiers & (MASK_CONTROL | MASK_ALT)) + gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers); else - mCallbacks->handleFocusLost(this); + mCallbacks->handleUnicodeChar(key, mKeyModifiers); } - } - if (event.active.state & SDL_APPACTIVE) - { - // Change in iconification/minimization state. - if ((!event.active.gain) != mIsMinimized) - { - mIsMinimized = (!event.active.gain); + break; + } - mCallbacks->handleActivate(this, !mIsMinimized); - LL_INFOS() << "SDL deiconification state switched to " << bool(event.active.gain) << LL_ENDL; - } - else - { - LL_INFOS() << "Ignored bogus redundant SDL deiconification state switch to " << bool(event.active.gain) << LL_ENDL; - } - } - break; + case SDL_EVENT_WINDOW_EXPOSED: + { + mCallbacks->handlePaint(this, 0, 0, 0, 0); + break; + } - case SDL_QUIT: - if(mCallbacks->handleCloseRequest(this, true)) - { - // Get the app to initiate cleanup. - mCallbacks->handleQuit(this); - // The app is responsible for calling destroyWindow when done with GL - } - break; - default: - //LL_INFOS() << "Unhandled SDL event type " << event.type << LL_ENDL; - break; + case SDL_EVENT_WINDOW_RESIZED: + { + LL_INFOS() << "Handling a resize event: " << event.window.data1 << "x" << event.window.data2 << LL_ENDL; + S32 width = llmax(event.window.data1, (S32)mMinWindowWidth); + S32 height = llmax(event.window.data2, (S32)mMinWindowHeight); + + mCallbacks->handleResize(this, width, height); + break; + } + case SDL_EVENT_WINDOW_MOUSE_ENTER: + break; + case SDL_EVENT_WINDOW_MOUSE_LEAVE: + mCallbacks->handleMouseLeave(this); + break; + case SDL_EVENT_WINDOW_FOCUS_GAINED: + //SDL_SetWindowKeyboardGrab(mWindow, true); + mCallbacks->handleFocus(this); + break; + case SDL_EVENT_WINDOW_FOCUS_LOST: + mCallbacks->handleFocusLost(this); + //SDL_SetWindowKeyboardGrab(mWindow, false); + break; + case SDL_EVENT_WINDOW_RESTORED: + mCallbacks->handleActivate(this, true); + break; + case SDL_EVENT_WINDOW_MAXIMIZED: + mCallbacks->handleActivate(this, true); + break; + case SDL_EVENT_WINDOW_MINIMIZED: + mCallbacks->handleActivate(this, false); + break; + case SDL_EVENT_WINDOW_DISPLAY_CHANGED: + { + mCallbacks->handleDisplayChanged(); + break; + } + case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: + { + S32 w, h = 0; + SDL_GetWindowSize(mWindow, &w, &h); + mCallbacks->handleDPIChanged(this, getSystemUISize(), w, h); + break; } + //case SDL_EVENT_WINDOW_SHOWN: + //case SDL_EVENT_WINDOW_HIDDEN: + //{ + // bool hidden = (flags & SDL_WINDOW_HIDDEN); + // mCallbacks->handleActivate(this, !hidden); + // break; + //} + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: + if(mCallbacks->handleCloseRequest(this, true)) + { + // Get the app to initiate cleanup. + mCallbacks->handleQuit(this); + // The app is responsible for calling destroyWindow when done with GL + } + break; + default: + break; } - updateCursor(); + return SDL_APP_CONTINUE; +} -#if LL_X11 - // This is a good time to stop flashing the icon if our mFlashTimer has - // expired. - if (mFlashing && mFlashTimer.hasExpired()) - { - x11_set_urgent(false); - mFlashing = false; - } -#endif // LL_X11 +// static +SDL_AppResult LLWindowSDL::handleEvents(const SDL_Event& event) +{ + if(!gWindowImplementation) return SDL_APP_CONTINUE; + + return gWindowImplementation->handleEvent(event); } static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty) { - SDL_Cursor *sdlcursor = NULL; + SDL_Cursor *sdlcursor = nullptr; SDL_Surface *bmpsurface; // Load cursor pixel data from BMP file @@ -1968,21 +1405,32 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty { SDL_Surface *cursurface; LL_DEBUGS() << "Loaded cursor file " << filename << " " - << bmpsurface->w << "x" << bmpsurface->h << LL_ENDL; - cursurface = SDL_CreateRGBSurface (SDL_SWSURFACE, - bmpsurface->w, - bmpsurface->h, - 32, - SDL_SwapLE32(0xFFU), - SDL_SwapLE32(0xFF00U), - SDL_SwapLE32(0xFF0000U), - SDL_SwapLE32(0xFF000000U)); - SDL_FillRect(cursurface, NULL, SDL_SwapLE32(0x00000000U)); + << bmpsurface->w << "x" << bmpsurface->h << LL_ENDL; + SDL_PixelFormat pix_format = SDL_GetPixelFormatForMasks(32, + SDL_Swap32LE(0xFFU), + SDL_Swap32LE(0xFF00U), + SDL_Swap32LE(0xFF0000U), + SDL_Swap32LE(0xFF000000U)); + if (pix_format == SDL_PIXELFORMAT_UNKNOWN) + { + return nullptr; + } + + const SDL_PixelFormatDetails* pix_format_details = SDL_GetPixelFormatDetails(pix_format); + if(!pix_format_details) + { + return nullptr; + } + + cursurface = SDL_CreateSurface(bmpsurface->w, + bmpsurface->h, + pix_format); + SDL_FillSurfaceRect(cursurface, nullptr, SDL_Swap32LE(0x00000000U)); // Blit the cursor pixel data onto a 32-bit RGBA surface so we // only have to cope with processing one type of pixel format. - if (0 == SDL_BlitSurface(bmpsurface, NULL, - cursurface, NULL)) + if (SDL_BlitSurface(bmpsurface, nullptr, + cursurface, nullptr)) { // n.b. we already checked that width is a multiple of 8. const int bitmap_bytes = (cursurface->w * cursurface->h) / 8; @@ -1997,33 +1445,33 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty for (i=0; ih; ++i) { for (j=0; jw; ++j) { U8 *pixelp = - ((U8*)cursurface->pixels) - + cursurface->pitch * i - + j*cursurface->format->BytesPerPixel; + ((U8*)cursurface->pixels) + + cursurface->pitch * i + + j*pix_format_details->bytes_per_pixel; U8 srcred = pixelp[0]; U8 srcgreen = pixelp[1]; U8 srcblue = pixelp[2]; bool mask_bit = (srcred != 200) - || (srcgreen != 200) - || (srcblue != 200); + || (srcgreen != 200) + || (srcblue != 200); bool data_bit = mask_bit && (srcgreen <= 80);//not 0x80 unsigned char bit_offset = (cursurface->w/8) * i - + j/8; + + j/8; cursor_data[bit_offset] |= (data_bit) << (7 - (j&7)); cursor_mask[bit_offset] |= (mask_bit) << (7 - (j&7)); } } sdlcursor = SDL_CreateCursor((Uint8*)cursor_data, - (Uint8*)cursor_mask, - cursurface->w, cursurface->h, - hotx, hoty); + (Uint8*)cursor_mask, + cursurface->w, cursurface->h, + hotx, hoty); delete[] cursor_data; delete[] cursor_mask; } else { LL_WARNS() << "CURSOR BLIT FAILURE, cursurface: " << cursurface << LL_ENDL; } - SDL_FreeSurface(cursurface); - SDL_FreeSurface(bmpsurface); + SDL_DestroySurface(cursurface); + SDL_DestroySurface(bmpsurface); } else { LL_WARNS() << "CURSOR LOAD FAILURE " << filename << LL_ENDL; } @@ -2033,12 +1481,6 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty void LLWindowSDL::updateCursor() { - if (ATIbug) { - // cursor-updating is very flaky when this bug is - // present; do nothing. - return; - } - if (mCurrentCursor != mNextCursor) { if (mNextCursor < UI_CURSOR_COUNT) @@ -2050,37 +1492,40 @@ void LLWindowSDL::updateCursor() sdlcursor = mSDLCursors[UI_CURSOR_ARROW]; if (sdlcursor) SDL_SetCursor(sdlcursor); - } else { + + mCurrentCursor = mNextCursor; + } + else + { LL_WARNS() << "Tried to set invalid cursor number " << mNextCursor << LL_ENDL; } - mCurrentCursor = mNextCursor; } } void LLWindowSDL::initCursors() { - int i; // Blank the cursor pointer array for those we may miss. - for (i=0; ibeforeDialog(); - - if (LLWindowSDL::ll_try_gtk_init()) + switch (type) { - GtkWidget *win = NULL; - - LL_INFOS() << "Creating a dialog because we're in windowed mode and GTK is happy." << LL_ENDL; - - GtkDialogFlags flags = GTK_DIALOG_MODAL; - GtkMessageType messagetype; - GtkButtonsType buttons; - switch (type) - { default: case OSMB_OK: - messagetype = GTK_MESSAGE_WARNING; - buttons = GTK_BUTTONS_OK; + oData.flags = SDL_MESSAGEBOX_WARNING; + oData.buttons = btnOk; + oData.numbuttons = 1; break; case OSMB_OKCANCEL: - messagetype = GTK_MESSAGE_QUESTION; - buttons = GTK_BUTTONS_OK_CANCEL; + oData.flags = SDL_MESSAGEBOX_INFORMATION; + oData.buttons = btnOkCancel; + oData.numbuttons = 2; break; case OSMB_YESNO: - messagetype = GTK_MESSAGE_QUESTION; - buttons = GTK_BUTTONS_YES_NO; + oData.flags = SDL_MESSAGEBOX_INFORMATION; + oData.buttons = btnYesNo; + oData.numbuttons = 2; break; - } - win = gtk_message_dialog_new(NULL, flags, messagetype, buttons, "%s", - text.c_str()); - -# if LL_X11 - // Make GTK tell the window manager to associate this - // dialog with our non-GTK SDL window, which should try - // to keep it on top etc. - if (gWindowImplementation && - gWindowImplementation->mSDL_XWindowID != None) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(gWindowImplementation->mSDL_XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } -# endif //LL_X11 - - gtk_window_set_position(GTK_WINDOW(win), - GTK_WIN_POS_CENTER_ON_PARENT); - - gtk_window_set_type_hint(GTK_WINDOW(win), - GDK_WINDOW_TYPE_HINT_DIALOG); - - if (!caption.empty()) - gtk_window_set_title(GTK_WINDOW(win), caption.c_str()); - - gint response = GTK_RESPONSE_NONE; - g_signal_connect (win, - "response", - G_CALLBACK (response_callback), - &response); + } - // we should be able to use a gtk_dialog_run(), but it's - // apparently not written to exist in a world without a higher - // gtk_main(), so we manage its signal/destruction outselves. - gtk_widget_show_all (win); - gtk_main(); + if(gWindowImplementation != nullptr) + gWindowImplementation->beforeDialog(); - //LL_INFOS() << "response: " << response << LL_ENDL; - switch (response) - { - case GTK_RESPONSE_OK: rtn = OSBTN_OK; break; - case GTK_RESPONSE_YES: rtn = OSBTN_YES; break; - case GTK_RESPONSE_NO: rtn = OSBTN_NO; break; - case GTK_RESPONSE_APPLY: rtn = OSBTN_OK; break; - case GTK_RESPONSE_NONE: - case GTK_RESPONSE_CANCEL: - case GTK_RESPONSE_CLOSE: - case GTK_RESPONSE_DELETE_EVENT: - default: rtn = OSBTN_CANCEL; - } - } - else + int btn{0}; + if(SDL_ShowMessageBox( &oData, &btn )) { - LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; - LL_INFOS() << "Skipping dialog because we're in fullscreen mode or GTK is not happy." << LL_ENDL; - rtn = OSBTN_OK; + if(gWindowImplementation != nullptr) + gWindowImplementation->afterDialog(); + return btn; } - if(gWindowImplementation != NULL) + if(gWindowImplementation != nullptr) gWindowImplementation->afterDialog(); - return rtn; + return OSBTN_CANCEL; } -static void color_changed_callback(GtkWidget *widget, - gpointer user_data) +bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) { - GtkColorSelection *colorsel = GTK_COLOR_SELECTION(widget); - GdkColor *colorp = (GdkColor*)user_data; - - gtk_color_selection_get_current_color(colorsel, colorp); + return false; } - /* Make the raw keyboard data available - used to poke through to LLQtWebKit so that Qt/Webkit has access to the virtual keycodes etc. that it needs */ LLSD LLWindowSDL::getNativeKeyData() { - LLSD result = LLSD::emptyMap(); + LLSD result = LLSD::emptyMap(); U32 modifiers = 0; // pretend-native modifiers... oh what a tangled web we weave! @@ -2367,140 +1735,21 @@ LLSD LLWindowSDL::getNativeKeyData() // what a plugin under GDK under Qt under SL under SDL under X11 considers // a 'native' modifier mask. this has been sort of reverse-engineered... they *appear* // to match GDK consts, but that may be co-incidence. - modifiers |= (mKeyModifiers & KMOD_LSHIFT) ? 0x0001 : 0; - modifiers |= (mKeyModifiers & KMOD_RSHIFT) ? 0x0001 : 0;// munge these into the same shift - modifiers |= (mKeyModifiers & KMOD_CAPS) ? 0x0002 : 0; - modifiers |= (mKeyModifiers & KMOD_LCTRL) ? 0x0004 : 0; - modifiers |= (mKeyModifiers & KMOD_RCTRL) ? 0x0004 : 0;// munge these into the same ctrl - modifiers |= (mKeyModifiers & KMOD_LALT) ? 0x0008 : 0;// untested - modifiers |= (mKeyModifiers & KMOD_RALT) ? 0x0008 : 0;// untested + modifiers |= (mKeyModifiers & SDL_KMOD_LSHIFT) ? 0x0001 : 0; + modifiers |= (mKeyModifiers & SDL_KMOD_RSHIFT) ? 0x0001 : 0;// munge these into the same shift + modifiers |= (mKeyModifiers & SDL_KMOD_CAPS) ? 0x0002 : 0; + modifiers |= (mKeyModifiers & SDL_KMOD_LCTRL) ? 0x0004 : 0; + modifiers |= (mKeyModifiers & SDL_KMOD_RCTRL) ? 0x0004 : 0;// munge these into the same ctrl + modifiers |= (mKeyModifiers & SDL_KMOD_LALT) ? 0x0008 : 0;// untested + modifiers |= (mKeyModifiers & SDL_KMOD_RALT) ? 0x0008 : 0;// untested // *todo: test ALTs - I don't have a case for testing these. Do you? // *todo: NUM? - I don't care enough right now (and it's not a GDK modifier). - result["scan_code"] = (S32)mKeyScanCode; - result["virtual_key"] = (S32)mKeyVirtualKey; + result["virtual_key"] = (S32)mKeyVirtualKey; + result["virtual_key_win"] = (S32)LLKeyboardSDL::mapSDL2toWin( mKeyVirtualKey ); result["modifiers"] = (S32)modifiers; - - return result; -} - - -bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ - bool rtn = false; - - beforeDialog(); - - if (ll_try_gtk_init()) - { - GtkWidget *win = NULL; - - win = gtk_color_selection_dialog_new(NULL); - -# if LL_X11 - // Get GTK to tell the window manager to associate this - // dialog with our non-GTK SDL window, which should try - // to keep it on top etc. - if (mSDL_XWindowID != None) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(mSDL_XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } -# endif //LL_X11 - - GtkColorSelection *colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG(win)->colorsel); - - GdkColor color, orig_color; - orig_color.pixel = 0; - orig_color.red = guint16(65535 * *r); - orig_color.green= guint16(65535 * *g); - orig_color.blue = guint16(65535 * *b); - color = orig_color; - - gtk_color_selection_set_previous_color (colorsel, &color); - gtk_color_selection_set_current_color (colorsel, &color); - gtk_color_selection_set_has_palette (colorsel, true); - gtk_color_selection_set_has_opacity_control(colorsel, false); - - gint response = GTK_RESPONSE_NONE; - g_signal_connect (win, - "response", - G_CALLBACK (response_callback), - &response); - - g_signal_connect (G_OBJECT (colorsel), "color_changed", - G_CALLBACK (color_changed_callback), - &color); - - gtk_window_set_modal(GTK_WINDOW(win), true); - gtk_widget_show_all(win); - // hide the help button - we don't service it. - gtk_widget_hide(GTK_COLOR_SELECTION_DIALOG(win)->help_button); - gtk_main(); - - if (response == GTK_RESPONSE_OK && - (orig_color.red != color.red - || orig_color.green != color.green - || orig_color.blue != color.blue) ) - { - *r = color.red / 65535.0f; - *g = color.green / 65535.0f; - *b = color.blue / 65535.0f; - rtn = true; - } - } - - afterDialog(); - - return rtn; -} -#else -S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) -{ - LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; - return 0; -} - -bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ - return (false); -} -#endif // LL_GTK - -#if LL_LINUX -// extracted from spawnWebBrowser for clarity and to eliminate -// compiler confusion regarding close(int fd) vs. LLWindow::close() -void exec_cmd(const std::string& cmd, const std::string& arg) -{ - char* const argv[] = {(char*)cmd.c_str(), (char*)arg.c_str(), NULL}; - fflush(NULL); - pid_t pid = fork(); - if (pid == 0) - { // child - // disconnect from stdin/stdout/stderr, or child will - // keep our output pipe undesirably alive if it outlives us. - close(0); - close(1); - close(2); - // end ourself by running the command - execv(cmd.c_str(), argv); /* Flawfinder: ignore */ - // if execv returns at all, there was a problem. - LL_WARNS() << "execv failure when trying to start " << cmd << LL_ENDL; - _exit(1); // _exit because we don't want atexit() clean-up! - } else { - if (pid > 0) - { - // parent - wait for child to die - int childExitStatus; - waitpid(pid, &childExitStatus, 0); - } else { - LL_WARNS() << "fork failure." << LL_ENDL; - } - } + return result; } -#endif // Open a URL with the user's default web browser. // Must begin with protocol identifier. @@ -2525,56 +1774,26 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) LL_INFOS() << "spawn_web_browser: " << escaped_url << LL_ENDL; -#if LL_LINUX -# if LL_X11 - if (mSDL_Display) - { - maybe_lock_display(); - // Just in case - before forking. - XSync(mSDL_Display, False); - maybe_unlock_display(); - } -# endif // LL_X11 - - std::string cmd, arg; - cmd = gDirUtilp->getAppRODataDir(); - cmd += gDirUtilp->getDirDelimiter(); - cmd += "etc"; - cmd += gDirUtilp->getDirDelimiter(); - cmd += "launch_url.sh"; - arg = escaped_url; - exec_cmd(cmd, arg); -#endif // LL_LINUX + if (!SDL_OpenURL(escaped_url.c_str())) + { + LL_WARNS() << "spawn_web_browser failed with error: " << SDL_GetError() << LL_ENDL; + } LL_INFOS() << "spawn_web_browser returning." << LL_ENDL; } - -void *LLWindowSDL::getPlatformWindow() +void* LLWindowSDL::getPlatformWindow() { -#if LL_GTK && LL_LLMOZLIB_ENABLED - if (LLWindowSDL::ll_try_gtk_init()) + void* ret = nullptr; + if (mWindow) { - maybe_lock_display(); - - GtkWidget *owin = gtk_window_new(GTK_WINDOW_POPUP); - // Why a layout widget? A MozContainer would be ideal, but - // it involves exposing Mozilla headers to mozlib-using apps. - // A layout widget with a GtkWindow parent has the desired - // properties of being plain GTK, having a window, and being - // derived from a GtkContainer. - GtkWidget *rtnw = gtk_layout_new(NULL, NULL); - gtk_container_add(GTK_CONTAINER(owin), rtnw); - gtk_widget_realize(rtnw); - GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(rtnw), GTK_NO_WINDOW); - - maybe_unlock_display(); - - return rtnw; +#if LL_WINDOWS + ret = SDL_GetPointerProperty(SDL_GetWindowProperties(mWindow), SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr); +#elif LL_DARWIN + ret = SDL_GetPointerProperty(SDL_GetWindowProperties(mWindow), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr); +#endif } -#endif // LL_GTK && LL_LLMOZLIB_ENABLED - // Unixoid mozilla really needs GTK. - return NULL; + return ret; } void LLWindowSDL::bringToFront() @@ -2582,20 +1801,17 @@ void LLWindowSDL::bringToFront() // This is currently used when we are 'launched' to a specific // map position externally. LL_INFOS() << "bringToFront" << LL_ENDL; -#if LL_X11 - if (mSDL_Display && !mFullscreen) + if (mWindow && !mFullscreen) { - maybe_lock_display(); - XRaiseWindow(mSDL_Display, mSDL_XWindowID); - XSync(mSDL_Display, False); - maybe_unlock_display(); + SDL_RaiseWindow(mWindow); } -#endif // LL_X11 } //static std::vector LLWindowSDL::getDynamicFallbackFontList() { + std::vector rtns; +#if LL_LINUX // Use libfontconfig to find us a nice ordered list of fallback fonts // specific to this system. std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf"); @@ -2612,9 +1828,9 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() // renderable range if for some reason our FreeType actually fails // to use some of the fonts we want it to. const bool elide_unicode_coverage = true; - std::vector rtns; - FcFontSet *fs = NULL; - FcPattern *sortpat = NULL; + + FcFontSet *fs = nullptr; + FcPattern *sortpat = nullptr; LL_INFOS() << "Getting system font list from FontConfig..." << LL_ENDL; @@ -2623,7 +1839,7 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() // of languages that can be displayed, but ensures that their // preferred language is rendered from a single consistent font where // possible. - FL_Locale *locale = NULL; + FL_Locale *locale = nullptr; FL_Success success = FL_FindLocale(&locale, FL_MESSAGES); if (success != 0) { @@ -2634,10 +1850,10 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() LL_INFOS("AppInit") << "Variant " << locale->variant << LL_ENDL; LL_INFOS() << "Preferring fonts of language: " - << locale->lang - << LL_ENDL; + << locale->lang + << LL_ENDL; sort_order = "lang=" + std::string(locale->lang) + ":" - + sort_order; + + sort_order; } } FL_FreeLocale(&locale); @@ -2654,8 +1870,7 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() { // Sort the list of system fonts from most-to-least-desirable. FcResult result; - fs = FcFontSort(NULL, sortpat, elide_unicode_coverage, - NULL, &result); + fs = FcFontSort(nullptr, sortpat, elide_unicode_coverage, nullptr, &result); FcPatternDestroy(sortpat); } @@ -2668,10 +1883,7 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() for (int i=0; infont; ++i) { FcChar8 *filename; - if (FcResultMatch == FcPatternGetString(fs->fonts[i], - FC_FILE, 0, - &filename) - && filename) + if (FcResultMatch == FcPatternGetString(fs->fonts[i], FC_FILE, 0, &filename) && filename) { rtns.push_back(std::string((const char*)filename)); if (rtns.size() >= max_font_count_cutoff) @@ -2682,16 +1894,101 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() } LL_DEBUGS() << "Using font list: " << LL_ENDL; - for (std::vector::iterator it = rtns.begin(); - it != rtns.end(); - ++it) + for (auto it = rtns.begin(); it != rtns.end(); ++it) { LL_DEBUGS() << " file: " << *it << LL_ENDL; } + LL_INFOS() << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << LL_ENDL; rtns.push_back(final_fallback); +#endif return rtns; } -#endif // LL_SDL +void LLWindowSDL::setLanguageTextInput(const LLCoordGL& position) +{ + LLCoordWindow win_pos; + convertCoords( position, &win_pos ); + + SDL_Rect r; + r.x = win_pos.mX; + r.y = win_pos.mY; + r.w = 500; + r.h = 16; + + SDL_SetTextInputArea(mWindow, &r, 0); +} + +F32 LLWindowSDL::getSystemUISize() +{ + if(mWindow) + { + F32 scale = SDL_GetWindowDisplayScale(mWindow); + if (scale > 0.0f) + { + return scale; + } + } + return 1.f; +} + +#if LL_DARWIN +// static +U64 LLWindowSDL::getVramSize() +{ + CGLRendererInfoObj info = 0; + GLint vram_megabytes = 0; + int num_renderers = 0; + CGLError the_err = CGLQueryRendererInfo (CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay), &info, &num_renderers); + if(0 == the_err) + { + // The name, uses, and other platform definitions of gGLManager.mVRAM suggest that this is supposed to be total vram in MB, + // rather than, say, just the texture memory. The two exceptions are: + // 1. LLAppViewer::getViewerInfo() puts the value in a field labeled "TEXTURE_MEMORY" + // 2. For years, this present function used kCGLRPTextureMemoryMegabytes + // Now we use kCGLRPVideoMemoryMegabytes to bring it in line with everything else (except thatone label). + CGLDescribeRenderer (info, 0, kCGLRPVideoMemoryMegabytes, &vram_megabytes); + CGLDestroyRendererInfo (info); + } + else + { + vram_megabytes = 256; + } + + return (U64)vram_megabytes; // return value is in megabytes. +} + +//static +void LLWindowSDL::setUseMultGL(bool use_mult_gl) +{ + bool was_enabled = sUseMultGL; + + sUseMultGL = use_mult_gl; + + if (gGLManager.mInited) + { + CGLContextObj ctx = CGLGetCurrentContext(); + //enable multi-threaded OpenGL (whether or not sUseMultGL actually changed) + if (sUseMultGL) + { + CGLError cgl_err = CGLEnable( ctx, kCGLCEMPEngine); + if (cgl_err != kCGLNoError ) + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; + sUseMultGL = false; + } + else + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; + } + } + else if (was_enabled) + { + CGLDisable( ctx, kCGLCEMPEngine); + LL_INFOS("GLInit") << "Multi-threaded OpenGL disabled." << LL_ENDL; + } + } +} +#endif + diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index 521d52df302..5c078eae32c 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -32,141 +32,152 @@ #include "llwindow.h" #include "lltimer.h" -#include "SDL/SDL.h" -#include "SDL/SDL_endian.h" - -#if LL_X11 -// get X11-specific headers for use in low-level stuff like copy-and-paste support -#include "SDL/SDL_syswm.h" -#endif - -// AssertMacros.h does bad things. -#include "fix_macros.h" -#undef verify -#undef require +#include "SDL3/SDL.h" +#include "SDL3/SDL_endian.h" +class LLPreeditor; -class LLWindowSDL : public LLWindow +class LLWindowSDL final : public LLWindow { public: - /*virtual*/ void show(); - /*virtual*/ void hide(); - /*virtual*/ void close(); - /*virtual*/ bool getVisible(); - /*virtual*/ bool getMinimized(); - /*virtual*/ bool getMaximized(); - /*virtual*/ bool maximize(); - /*virtual*/ void minimize(); - /*virtual*/ void restore(); - /*virtual*/ bool getFullscreen(); - /*virtual*/ bool getPosition(LLCoordScreen *position); - /*virtual*/ bool getSize(LLCoordScreen *size); - /*virtual*/ bool getSize(LLCoordWindow *size); - /*virtual*/ bool setPosition(LLCoordScreen position); - /*virtual*/ bool setSizeImpl(LLCoordScreen size); - /*virtual*/ bool setSizeImpl(LLCoordWindow size); - /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool disable_vsync, const LLCoordScreen * const posp = NULL); - /*virtual*/ bool setCursorPosition(LLCoordWindow position); - /*virtual*/ bool getCursorPosition(LLCoordWindow *position); - /*virtual*/ bool isWrapMouse() const override { return true; } - /*virtual*/ void showCursor(); - /*virtual*/ void hideCursor(); - /*virtual*/ void showCursorFromMouseMove(); - /*virtual*/ void hideCursorUntilMouseMove(); - /*virtual*/ bool isCursorHidden(); - /*virtual*/ void updateCursor(); - /*virtual*/ void captureMouse(); - /*virtual*/ void releaseMouse(); - /*virtual*/ void setMouseClipping( bool b ); - /*virtual*/ void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); - - /*virtual*/ bool isClipboardTextAvailable(); - /*virtual*/ bool pasteTextFromClipboard(LLWString &dst); - /*virtual*/ bool copyTextToClipboard(const LLWString & src); - - /*virtual*/ bool isPrimaryTextAvailable(); - /*virtual*/ bool pasteTextFromPrimary(LLWString &dst); - /*virtual*/ bool copyTextToPrimary(const LLWString & src); - - /*virtual*/ void flashIcon(F32 seconds); - /*virtual*/ F32 getGamma(); - /*virtual*/ bool setGamma(const F32 gamma); // Set the gamma - /*virtual*/ U32 getFSAASamples(); - /*virtual*/ void setFSAASamples(const U32 samples); - /*virtual*/ bool restoreGamma(); // Restore original gamma table (before updating gamma) - /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } - /*virtual*/ void processMiscNativeEvents(); - /*virtual*/ void gatherInput(); - /*virtual*/ void swapBuffers(); - /*virtual*/ void restoreGLContext() {}; - - /*virtual*/ void delayInputProcessing() { }; + void show() override; + void hide() override; + void restore() override; + + void close() override; + + bool getVisible() override; + + bool getMinimized() override; + + bool getMaximized() override; + + bool maximize() override; + void minimize() override; + + bool getPosition(LLCoordScreen *position) override; + + bool getSize(LLCoordScreen *size) override; + bool getSize(LLCoordWindow *size) override; + + bool setPosition(LLCoordScreen position) override; + + bool setSizeImpl(LLCoordScreen size) override; + bool setSizeImpl(LLCoordWindow size) override; + + bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, + const LLCoordScreen *const posp = NULL) override; + + bool setCursorPosition(LLCoordWindow position) override; + + bool getCursorPosition(LLCoordWindow *position) override; + bool isWrapMouse() const override { return true; } + void showCursor() override; + void hideCursor() override; + bool isCursorHidden() override; + + void showCursorFromMouseMove() override; + void hideCursorUntilMouseMove() override; + + void updateCursor() override; + + void captureMouse() override; + void releaseMouse() override; + + void setMouseClipping(bool b) override; + + void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true) override; + + bool isClipboardTextAvailable() override; + bool pasteTextFromClipboard(LLWString &dst) override; + bool copyTextToClipboard(const LLWString &src) override; + + bool isPrimaryTextAvailable() override; + bool pasteTextFromPrimary(LLWString &dst) override; + bool copyTextToPrimary(const LLWString &src) override; + + void flashIcon(F32 seconds) override; + void maybeStopFlashIcon(); + + F32 getGamma() override; + bool setGamma(const F32 gamma) override; // Set the gamma + bool restoreGamma() override; // Restore original gamma table (before updating gamma) + + U32 getFSAASamples() override; + void setFSAASamples(const U32 samples) override; + + void processMiscNativeEvents() override; + + void gatherInput() override; + + SDL_AppResult handleEvent(const SDL_Event& event); + static SDL_AppResult handleEvents(const SDL_Event& event); + + void swapBuffers() override; + + void delayInputProcessing() override {}; // handy coordinate space conversion routines - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to); - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to); - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to); - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to); - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to); - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to); + bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override; + bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override; + bool convertCoords(LLCoordWindow from, LLCoordGL *to) override; + bool convertCoords(LLCoordGL from, LLCoordWindow *to) override; + bool convertCoords(LLCoordScreen from, LLCoordGL *to) override; + bool convertCoords(LLCoordGL from, LLCoordScreen *to) override; + + LLWindowResolution *getSupportedResolutions(S32 &num_resolutions) override; + + F32 getNativeAspectRatio() override; + F32 getPixelAspectRatio() override; + void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); - /*virtual*/ F32 getNativeAspectRatio(); - /*virtual*/ F32 getPixelAspectRatio(); - /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } + void beforeDialog() override; + void afterDialog() override; - /*virtual*/ void beforeDialog(); - /*virtual*/ void afterDialog(); + bool dialogColorPicker(F32 *r, F32 *g, F32 *b) override; - /*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b); + void *getPlatformWindow() override; - /*virtual*/ void *getPlatformWindow(); - /*virtual*/ void bringToFront(); + void bringToFront() override; - /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); + void setLanguageTextInput(const LLCoordGL& pos) override; + + void spawnWebBrowser(const std::string &escaped_url, bool async) override; + + void setTitle(const std::string title) override; static std::vector getDynamicFallbackFontList(); - // Not great that these are public, but they have to be accessible - // by non-class code and it's better than making them global. -#if LL_X11 - Window mSDL_XWindowID; - Display *mSDL_Display; -#endif - void (*Lock_Display)(void); - void (*Unlock_Display)(void); + void *createSharedContext() override; + void makeContextCurrent(void *context) override; + void destroySharedContext(void *context) override; + void toggleVSync(bool enable_vsync) override; -#if LL_GTK - // Lazily initialize and check the runtime GTK version for goodness. - static bool ll_try_gtk_init(void); -#endif // LL_GTK + F32 getSystemUISize() override; -#if LL_X11 - static Window get_SDL_XWindowID(void); - static Display* get_SDL_Display(void); -#endif // LL_X11 + static std::vector getDisplaysResolutionList(); -protected: - LLWindowSDL(LLWindowCallbacks* callbacks, - const std::string& title, int x, int y, int width, int height, U32 flags, - bool fullscreen, bool clearBg, bool disable_vsync, bool use_gl, - bool ignore_pixel_depth, U32 fsaa_samples); - ~LLWindowSDL(); +#if LL_DARWIN + static U64 getVramSize(); + static void setUseMultGL(bool use_mult_gl); + + static bool sUseMultGL; +#endif - /*virtual*/ bool isValid(); - /*virtual*/ LLSD getNativeKeyData(); +protected: + LLWindowSDL(LLWindowCallbacks *callbacks, + const std::string &title, const std::string& name, int x, int y, int width, int height, U32 flags, + bool fullscreen, bool clearBg, bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples); - void initCursors(); - void quitCursors(); - void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); + ~LLWindowSDL(); - // Changes display resolution. Returns true if successful - bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + bool isValid() override; - // Go back to last fullscreen display resolution. - bool setFullscreenResolution(); + LLSD getNativeKeyData() override; - bool shouldPostQuit() { return mPostQuit; } + void initCursors(); + void quitCursors(); protected: // @@ -174,57 +185,49 @@ class LLWindowSDL : public LLWindow // // create or re-create the GL context/window. Called from the constructor and switchContext(). - bool createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool disable_vsync); + bool createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync); void destroyContext(); - void setupFailure(const std::string& text, const std::string& caption, U32 type); - void fixWindowSize(void); - U32 SDLCheckGrabbyKeys(SDLKey keysym, bool gain); + + void setupFailure(const std::string &text, const std::string &caption, U32 type); + bool SDLReallyCaptureInput(bool capture); + U32 SDLCheckGrabbyKeys(U32 keysym, bool gain); // // Platform specific variables // - U32 mGrabbyKeyFlags; - int mReallyCapturedCount; - SDL_Surface * mWindow; - std::string mWindowTitle; - double mOriginalAspectRatio; - bool mNeedsResize; // Constructor figured out the window is too big, it needs a resize. - LLCoordScreen mNeedsResizeSize; - F32 mOverrideAspectRatio; - F32 mGamma; - U32 mFSAASamples; + U32 mGrabbyKeyFlags = 0; - int mSDLFlags; + SDL_Window *mWindow = nullptr; + SDL_GLContext mContext; + SDL_Cursor *mSDLCursors[UI_CURSOR_COUNT]; - SDL_Cursor* mSDLCursors[UI_CURSOR_COUNT]; - int mHaveInputFocus; /* 0=no, 1=yes, else unknown */ - int mIsMinimized; /* 0=no, 1=yes, else unknown */ + std::string mWindowTitle; + F32 mOriginalAspectRatio = 1.0f; + F32 mOverrideAspectRatio = 0.0f; + F32 mGamma = 0.0f; + U32 mFSAASamples = 0; friend class LLWindowManager; private: -#if LL_X11 - void x11_set_urgent(bool urgent); - bool mFlashing; + bool mFlashing = false; LLTimer mFlashTimer; -#endif //LL_X11 + U32 mKeyVirtualKey = 0; + U32 mKeyModifiers = SDL_KMOD_NONE; - U32 mKeyScanCode; - U32 mKeyVirtualKey; - SDLMod mKeyModifiers; + void tryFindFullscreenSize(int &aWidth, int &aHeight); }; - class LLSplashScreenSDL : public LLSplashScreen { public: LLSplashScreenSDL(); virtual ~LLSplashScreenSDL(); - /*virtual*/ void showImpl(); - /*virtual*/ void updateImpl(const std::string& mesg); - /*virtual*/ void hideImpl(); + void showImpl() override; + void updateImpl(const std::string& mesg) override; + void hideImpl() override; }; S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type); diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt index 972bb7dd2de..600db532d26 100644 --- a/indra/media_plugins/CMakeLists.txt +++ b/indra/media_plugins/CMakeLists.txt @@ -1,20 +1,10 @@ # -*- cmake -*- add_subdirectory(base) +add_subdirectory(cef) +add_subdirectory(libvlc) +add_subdirectory(example) if (LINUX) - #add_subdirectory(gstreamer010) - add_subdirectory(example) + add_subdirectory(gstreamer10) endif (LINUX) - -if (DARWIN) - add_subdirectory(cef) - add_subdirectory(libvlc) - add_subdirectory(example) -endif (DARWIN) - -if (WINDOWS) - add_subdirectory(cef) - add_subdirectory(libvlc) - add_subdirectory(example) -endif (WINDOWS) diff --git a/indra/media_plugins/base/media_plugin_base.cpp b/indra/media_plugins/base/media_plugin_base.cpp index ccaa43cfb50..2e1e43d9e84 100644 --- a/indra/media_plugins/base/media_plugin_base.cpp +++ b/indra/media_plugins/base/media_plugin_base.cpp @@ -167,6 +167,55 @@ void MediaPluginBase::sendStatus() sendMessage(message); } +#if LL_LINUX + +#include + +size_t SymbolGrabber::registerSymbol( SymbolToGrab aSymbol ) +{ + gSymbolsToGrab.emplace_back(aSymbol); + return gSymbolsToGrab.size(); +} + +bool SymbolGrabber::grabSymbols(std::vector< std::string > const &aDSONames) +{ + if (sSymsGrabbed) + return true; + + for( std::vector< std::string >::const_iterator itr = aDSONames.begin(); itr != aDSONames.end(); ++itr ) + { + auto pDSO = dlopen( itr->c_str(), RTLD_NOW ); + + if( pDSO ) + { + sLoadedLibraries.push_back(pDSO); + + for (auto i = 0; i < gSymbolsToGrab.size(); ++i) + { + if (!*gSymbolsToGrab[i].mPPFunc) + *gSymbolsToGrab[i].mPPFunc = dlsym(pDSO, gSymbolsToGrab[i].mName); + } + } + } + + bool sym_error = false; + + for( auto i = 0; i < gSymbolsToGrab.size(); ++i ) + { + if( gSymbolsToGrab[ i ].mRequired && ! *gSymbolsToGrab[ i ].mPPFunc ) + sym_error = true; + } + + sSymsGrabbed = !sym_error; + return sSymsGrabbed; +} + +void SymbolGrabber::ungrabSymbols() +{ + +} +#endif + #if LL_WINDOWS # define LLSYMEXPORT __declspec(dllexport) @@ -202,3 +251,50 @@ int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* param return 1; } #endif + +#if LL_LINUX +pid_t getParentPid( pid_t aPid ) +{ + std::stringstream strm; + strm << "/proc/" << aPid << "/status"; + std::ifstream in{ strm.str() }; + + if( !in.is_open() ) + return 0; + + pid_t res {0}; + while( !in.eof() && res == 0 ) + { + std::string line; + line.resize( 1024, 0 ); + in.getline( &line[0], line.length() ); + + auto i = line.find( "PPid:" ); + + if( i == std::string::npos ) + continue; + + char const *pIn = line.c_str() + 5; // Skip over pid; + while( *pIn != 0 && isspace( *pIn ) ) + ++pIn; + + if( *pIn ) + res = atoll( pIn ); + } + return res; +} + +bool isPluginPid( pid_t aPid ) +{ + auto myPid = getpid(); + + do + { + if( aPid == myPid ) + return true; + aPid = getParentPid( aPid ); + } while( aPid > 1 ); + + return false; +} +#endif diff --git a/indra/media_plugins/base/media_plugin_base.h b/indra/media_plugins/base/media_plugin_base.h index f65c712a66b..0f014f83355 100644 --- a/indra/media_plugins/base/media_plugin_base.h +++ b/indra/media_plugins/base/media_plugin_base.h @@ -32,6 +32,40 @@ #include "llpluginmessage.h" #include "llpluginmessageclasses.h" +#if LL_LINUX + +struct SymbolToGrab +{ + bool mRequired; + char const *mName; + void **mPPFunc; +}; + +class SymbolGrabber +{ +public: + size_t registerSymbol( SymbolToGrab aSymbol ); + bool grabSymbols(std::vector< std::string > const &aDSONames); + void ungrabSymbols(); + +private: + std::vector< SymbolToGrab > gSymbolsToGrab; + + bool sSymsGrabbed = false; + std::vector sLoadedLibraries; +}; + +extern SymbolGrabber gSymbolGrabber; + +// extern SymbolGrabber gSymbolGrabber; + +#define LL_GRAB_SYM(SYMBOL_GRABBER, REQUIRED, SYMBOL_NAME, RETURN, ...) \ + RETURN (*ll##SYMBOL_NAME)(__VA_ARGS__) = nullptr; \ + size_t gRegistered##SYMBOL_NAME = SYMBOL_GRABBER.registerSymbol( \ + { REQUIRED, #SYMBOL_NAME , (void**)&ll##SYMBOL_NAME} \ + ); + +#endif class MediaPluginBase { @@ -126,4 +160,7 @@ int init_media_plugin( LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); - +#if LL_LINUX +pid_t getParentPid(pid_t aPid); +bool isPluginPid(pid_t aPid); +#endif diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt index dc2d82017d0..f78572e97c1 100644 --- a/indra/media_plugins/cef/CMakeLists.txt +++ b/indra/media_plugins/cef/CMakeLists.txt @@ -10,7 +10,7 @@ include(Linking) include(PluginAPI) include(CEFPlugin) - +include(GLIB) ### media_plugin_cef @@ -24,16 +24,34 @@ set(media_plugin_cef_HEADER_FILES # Select which VolumeCatcher implementation to use if (LINUX) - message(FATAL_ERROR "CEF plugin has been enabled for a Linux compile.\n" - " Please create a volume_catcher implementation for this platform.") + foreach( PULSE_FILE pulse/introspect.h pulse/context.h pulse/subscribe.h pulse/glib-mainloop.h ) + find_path( PULSE_FILE_${PULSE_FILE}_FOUND ${PULSE_FILE} NO_CACHE) + if( NOT PULSE_FILE_${PULSE_FILE}_FOUND ) + message( "Looking for ${PULSE_FILE} ... not found") + message( FATAL_ERROR "Pulse header not found" ) + else() + message( "Looking for ${PULSE_FILE} ... found") + endif() + endforeach() + + include(FindPipeWire) + include_directories(SYSTEM ${PIPEWIRE_INCLUDE_DIRS} ${SPA_INCLUDE_DIRS}) + + message( "Building with Linux volume catcher for PipeWire and PulseAudio" ) + + list(APPEND media_plugin_cef_HEADER_FILES + linux/volume_catcher_linux.h + ) + + set(LINUX_VOLUME_CATCHER + linux/volume_catcher_linux.cpp + linux/volume_catcher_pulseaudio.cpp + linux/volume_catcher_pipewire.cpp + ) + + list(APPEND media_plugin_cef_SOURCE_FILES ${LINUX_VOLUME_CATCHER}) elseif (DARWIN) - list(APPEND media_plugin_cef_SOURCE_FILES mac_volume_catcher_null.cpp) - find_library(CORESERVICES_LIBRARY CoreServices) - find_library(AUDIOUNIT_LIBRARY AudioUnit) - set( media_plugin_cef_LINK_LIBRARIES - ${CORESERVICES_LIBRARY} # for Component Manager calls - ${AUDIOUNIT_LIBRARY} # for AudioUnit calls - ) + list(APPEND media_plugin_cef_SOURCE_FILES volume_catcher_null.cpp) elseif (WINDOWS) list(APPEND media_plugin_cef_SOURCE_FILES windows_volume_catcher.cpp) endif (LINUX) @@ -52,6 +70,7 @@ add_library(media_plugin_cef target_link_libraries(media_plugin_cef media_plugin_base ll::cef + ll::glib_headers ) if (WINDOWS) @@ -63,6 +82,14 @@ if (WINDOWS) endif (WINDOWS) if (DARWIN) + find_library(CORESERVICES_LIBRARY CoreServices) + find_library(AUDIOUNIT_LIBRARY AudioUnit) + + target_link_libraries(media_plugin_cef + ${CORESERVICES_LIBRARY} # for Component Manager calls + ${AUDIOUNIT_LIBRARY} # for AudioUnit calls + ) + # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name set_target_properties( media_plugin_cef @@ -73,4 +100,6 @@ if (DARWIN) LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) -endif (DARWIN) +elseif (LINUX) + target_link_options(media_plugin_cef PRIVATE "LINKER:--build-id" "LINKER:-rpath,'$ORIGIN:$ORIGIN/../../lib'") +endif () diff --git a/indra/media_plugins/cef/linux/volume_catcher_linux.cpp b/indra/media_plugins/cef/linux/volume_catcher_linux.cpp new file mode 100644 index 00000000000..7d332420630 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_linux.cpp @@ -0,0 +1,78 @@ +/** + * @file volume_catcher.cpp + * @brief Linux volume catcher which will pick an implementation to use + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * @endcond + */ + +#include "volume_catcher_linux.h" + +VolumeCatcher::VolumeCatcher() +{ +} + +void VolumeCatcher::onEnablePipeWireVolumeCatcher(bool enable) +{ + if (pimpl != nullptr) + return; + + if (enable) + { + LL_DEBUGS() << "volume catcher using pipewire" << LL_ENDL; + pimpl = new VolumeCatcherPipeWire(); + } + else + { + LL_DEBUGS() << "volume catcher using pulseaudio" << LL_ENDL; + pimpl = new VolumeCatcherPulseAudio(); + } +} + +VolumeCatcher::~VolumeCatcher() +{ + if (pimpl != nullptr) + { + delete pimpl; + pimpl = nullptr; + } +} + +void VolumeCatcher::setVolume(F32 volume) +{ + if (pimpl != nullptr) { + pimpl->setVolume(volume); + } +} + +void VolumeCatcher::setPan(F32 pan) +{ + if (pimpl != nullptr) + pimpl->setPan(pan); +} + +void VolumeCatcher::pump() +{ + if (pimpl != nullptr) + pimpl->pump(); +} diff --git a/indra/media_plugins/cef/linux/volume_catcher_linux.h b/indra/media_plugins/cef/linux/volume_catcher_linux.h new file mode 100644 index 00000000000..505f9ffb314 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_linux.h @@ -0,0 +1,149 @@ +/** + * @file volume_catcher_impl.h + * @brief + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * @endcond + */ + +#ifndef VOLUME_CATCHER_LINUX_H +#define VOLUME_CATCHER_LINUX_H + +#include "linden_common.h" + +#include "../volume_catcher.h" + +#include +#include + +extern "C" { +// There's no special reason why we want the *glib* PA mainloop, but the generic polling implementation seems broken. +#include +#include + +#include + +#include "apr_pools.h" +#include "apr_dso.h" +} + +#include "media_plugin_base.h" + +class VolumeCatcherImpl +{ +public: + virtual ~VolumeCatcherImpl() = default; + + virtual void setVolume(F32 volume) = 0; // 0.0 - 1.0 + + // Set the left-right pan of audio sources + // where -1.0 = left, 0 = center, and 1.0 = right + virtual void setPan(F32 pan) = 0; + + virtual void pump() = 0; // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume +}; + +class VolumeCatcherPulseAudio : public VolumeCatcherImpl +{ +public: + VolumeCatcherPulseAudio(); + ~VolumeCatcherPulseAudio(); + + void setVolume(F32 volume); + void setPan(F32 pan); + void pump(); + + // for internal use - can't be private because used from our C callbacks + + bool loadsyms(std::string pa_dso_name); + void init(); + void cleanup(); + + void update_all_volumes(F32 volume); + void update_index_volume(U32 index, F32 volume); + void connected_okay(); + + std::set mSinkInputIndices; + std::map mSinkInputNumChannels; + F32 mDesiredVolume; + pa_glib_mainloop *mMainloop; + pa_context *mPAContext; + bool mConnected; + bool mGotSyms; +}; + +class VolumeCatcherPipeWire : public VolumeCatcherImpl +{ +public: + VolumeCatcherPipeWire(); + ~VolumeCatcherPipeWire(); + + bool loadsyms(std::string pw_dso_name); + void init(); + void cleanup(); + + // some of these should be private + + void lock(); + void unlock(); + + void setVolume(F32 volume); + void setPan(F32 pan); + void pump(); + + void handleRegistryEventGlobal( + uint32_t id, uint32_t permissions, const char* type, + uint32_t version, const struct spa_dict* props + ); + + class ChildNode + { + public: + bool mActive = false; + + pw_proxy* mProxy = nullptr; + spa_hook mNodeListener {}; + spa_hook mProxyListener {}; + VolumeCatcherPipeWire* mImpl = nullptr; + + void updateVolume(); + void destroy(); + }; + + bool mGotSyms = false; + + F32 mVolume = 1.0f; // max by default + // F32 mPan = 0.0f; // center + + pw_thread_loop* mThreadLoop = nullptr; + pw_context* mContext = nullptr; + pw_core* mCore = nullptr; + pw_registry* mRegistry = nullptr; + spa_hook mRegistryListener; + + std::unordered_set mChildNodes; + std::mutex mChildNodesMutex; + std::mutex mCleanupMutex; +}; + +#endif // VOLUME_CATCHER_LINUX_H diff --git a/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp b/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp new file mode 100755 index 00000000000..73ef7fc18cb --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp @@ -0,0 +1,333 @@ +/** + * @file volume_catcher_pipewire.cpp + * @brief A Linux-specific, PipeWire-specific hack to detect and volume-adjust new audio sources + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * @endcond + */ + +/* + The high-level design is as follows: + 1) Connect to the PipeWire daemon + 2) Find all existing and new audio nodes + 3) Examine PID and parent PID's to see if it belongs to our process + 4) If so, tell PipeWire to adjust the volume of that node + 5) Keep a list of all audio nodes and adjust when we setVolume() + */ + +#include "linden_common.h" + +#include "volume_catcher_linux.h" + +extern "C" { +#include +#include +} + +SymbolGrabber pwSymbolGrabber; + +#include "volume_catcher_pipewire_syms.inc" + +//////////////////////////////////////////////////// + +VolumeCatcherPipeWire::VolumeCatcherPipeWire() +{ + init(); +} + +VolumeCatcherPipeWire::~VolumeCatcherPipeWire() +{ + cleanup(); +} + +static void registryEventGlobal( + void *data, uint32_t id, uint32_t permissions, const char *type, + uint32_t version, const struct spa_dict *props) +{ + static_cast(data)->handleRegistryEventGlobal( + id, permissions, type, version, props + ); +} + +static const struct pw_registry_events REGISTRY_EVENTS = { + .version = PW_VERSION_REGISTRY_EVENTS, + .global = registryEventGlobal, +}; + +bool VolumeCatcherPipeWire::loadsyms(std::string pw_dso_name) +{ + return pwSymbolGrabber.grabSymbols({ pw_dso_name }); +} + +void VolumeCatcherPipeWire::init() +{ + LL_DEBUGS() << "init" << LL_ENDL; + + mGotSyms = loadsyms("libpipewire-0.3.so.0"); + + if (!mGotSyms) + return; + + LL_DEBUGS() << "successfully got symbols" << LL_ENDL; + + llpw_init(nullptr, nullptr); + + mThreadLoop = llpw_thread_loop_new("SL Plugin Volume Adjuster", nullptr); + + if (!mThreadLoop) + return; + + // i dont think we need to lock this early + // std::lock_guard pwLock(*this); + + mContext = llpw_context_new( + llpw_thread_loop_get_loop(mThreadLoop), nullptr, 0 + ); + + if (!mContext) + return; + + mCore = llpw_context_connect(mContext, nullptr, 0); + + if (!mCore) + return; + + mRegistry = pw_core_get_registry(mCore, PW_VERSION_REGISTRY, 0); + + LL_DEBUGS() << "pw_core_get_registry: " << (mRegistry?"success":"nullptr") << LL_ENDL; + + spa_zero(mRegistryListener); + + pw_registry_add_listener( + mRegistry, &mRegistryListener, ®ISTRY_EVENTS, this + ); + + llpw_thread_loop_start(mThreadLoop); + + LL_DEBUGS() << "thread loop started" << LL_ENDL; +} + +void VolumeCatcherPipeWire::cleanup() +{ + { + std::unique_lock childNodesLock(mChildNodesMutex); + for (auto *childNode: mChildNodes) + childNode->destroy(); + + mChildNodes.clear(); + } + + { + std::unique_lock pwLock(mCleanupMutex); + if (mRegistry) + llpw_proxy_destroy((struct pw_proxy *) mRegistry); + + spa_zero(mRegistryListener); + + if (mCore) + llpw_core_disconnect(mCore); + if (mContext) + llpw_context_destroy(mContext); + } + + if (!mThreadLoop) + return; + + llpw_thread_loop_stop(mThreadLoop); + llpw_thread_loop_destroy(mThreadLoop); + + LL_DEBUGS() << "cleanup done" << LL_ENDL; +} + +void VolumeCatcherPipeWire::lock() +{ + if (!mThreadLoop) + return; + + llpw_thread_loop_lock(mThreadLoop); +} + +void VolumeCatcherPipeWire::unlock() +{ + if (!mThreadLoop) + return; + + llpw_thread_loop_unlock(mThreadLoop); +} + +const uint32_t channels = 1; +const float resetVolumes[channels] = { 1.0f }; + +void VolumeCatcherPipeWire::ChildNode::updateVolume() +{ + if (!mActive) + return; + + F32 volume = std::clamp(mImpl->mVolume, 0.0f, 1.0f); + + const float volumes[channels] = { volume }; + + uint8_t buffer[512]; + + spa_pod_builder builder; + spa_pod_builder_init(&builder, buffer, sizeof(buffer)); + + spa_pod_frame frame; + spa_pod_builder_push_object(&builder, &frame, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props); + + // resets system-wide memorized volume for chromium (not google chrome) to 100% + spa_pod_builder_prop(&builder, SPA_PROP_channelVolumes, 0); + spa_pod_builder_array(&builder, sizeof(float), SPA_TYPE_Float, channels, resetVolumes); + + // sets temporary volume + spa_pod_builder_prop(&builder, SPA_PROP_softVolumes, 0); + spa_pod_builder_array(&builder, sizeof(float), SPA_TYPE_Float, channels, volumes); + + spa_pod* pod = static_cast(spa_pod_builder_pop(&builder, &frame)); + + { + std::lock_guard pwLock(*mImpl); + pw_node_set_param((pw_node*)mProxy, SPA_PARAM_Props, 0, pod); + } +} + +void VolumeCatcherPipeWire::ChildNode::destroy() +{ + if (!mActive) + return; + + mActive = false; + + { + std::unique_lock childNodesLock(mImpl->mChildNodesMutex); + mImpl->mChildNodes.erase(this); + } + + spa_hook_remove(&mNodeListener); + spa_hook_remove(&mProxyListener); + + { + std::lock_guard pwLock(*mImpl); + llpw_proxy_destroy(mProxy); + } +} + +static void nodeEventInfo(void* data, const struct pw_node_info* info) +{ + const char* processId = spa_dict_lookup(info->props, PW_KEY_APP_PROCESS_ID); + + if (processId == nullptr) + return; + + pid_t pid = atoll(processId); + + if (!isPluginPid(pid)) + return; + + const char* appName = spa_dict_lookup(info->props, PW_KEY_APP_NAME); + LL_DEBUGS() << "got app: " << appName << LL_ENDL; + + auto* const childNode = static_cast(data); + LL_DEBUGS() << "init volume: " << childNode->mImpl->mVolume << LL_ENDL; + + childNode->updateVolume(); + + { + std::lock_guard childNodesLock(childNode->mImpl->mChildNodesMutex); + childNode->mImpl->mChildNodes.insert(childNode); + } +} + +static const struct pw_node_events NODE_EVENTS = { + .version = PW_VERSION_CLIENT_EVENTS, + .info = nodeEventInfo, +}; + +static void proxyEventDestroy(void* data) +{ + auto* const childNode = static_cast(data); + childNode->destroy(); +} + +static void proxyEventRemoved(void* data) +{ + auto* const childNode = static_cast(data); + childNode->destroy(); +} + +static const struct pw_proxy_events PROXY_EVENTS = { + .version = PW_VERSION_PROXY_EVENTS, + .destroy = proxyEventDestroy, + .removed = proxyEventRemoved, +}; + +void VolumeCatcherPipeWire::handleRegistryEventGlobal( + uint32_t id, uint32_t permissions, const char *type, uint32_t version, + const struct spa_dict *props) +{ + if (props == nullptr || type == nullptr || strcmp(type, PW_TYPE_INTERFACE_Node) != 0) + return; + + const char* mediaClass = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS); + + if (mediaClass == nullptr || strcmp(mediaClass, "Stream/Output/Audio") != 0) + return; + + pw_proxy* proxy = static_cast( + pw_registry_bind(mRegistry, id, type, PW_VERSION_CLIENT, sizeof(ChildNode)) + ); + + auto* const childNode = static_cast(llpw_proxy_get_user_data(proxy)); + + childNode->mActive = true; + childNode->mProxy = proxy; + childNode->mImpl = this; + + pw_node_add_listener((pw_node*)proxy, &childNode->mNodeListener, &NODE_EVENTS, childNode); + llpw_proxy_add_listener(proxy, &childNode->mProxyListener, &PROXY_EVENTS, childNode); +} + +void VolumeCatcherPipeWire::setVolume(F32 volume) +{ + LL_DEBUGS() << "setting volume to: " << volume << LL_ENDL; + + mVolume = volume; + + { + std::unique_lock childNodeslock(mChildNodesMutex); + std::unordered_set copyOfChildNodes(mChildNodes); + + LL_DEBUGS() << "found " << copyOfChildNodes.size() << " child nodes" << LL_ENDL; + + for (auto* childNode : copyOfChildNodes) + childNode->updateVolume(); + } +} + +void VolumeCatcherPipeWire::setPan(F32 pan) +{ +} + +void VolumeCatcherPipeWire::pump() +{ +} diff --git a/indra/media_plugins/cef/linux/volume_catcher_pipewire_syms.inc b/indra/media_plugins/cef/linux/volume_catcher_pipewire_syms.inc new file mode 100644 index 00000000000..dbc0f5f169d --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_pipewire_syms.inc @@ -0,0 +1,26 @@ +#define G pwSymbolGrabber + +// required symbols to grab +LL_GRAB_SYM(G, true, pw_init, void, int *argc, char **argv[]); +// LL_GRAB_SYM(G, true, pw_main_loop_new, struct pw_main_loop *, const struct spa_dict *props); +// LL_GRAB_SYM(G, true, pw_main_loop_get_loop, struct pw_loop *, struct pw_main_loop *loop); +// LL_GRAB_SYM(G, true, pw_main_loop_destroy, void, struct pw_main_loop *loop); +// LL_GRAB_SYM(G, true, pw_main_loop_run, void, struct pw_main_loop *loop); +LL_GRAB_SYM(G, true, pw_context_new, struct pw_context *, struct pw_loop *main_loop, struct pw_properties *props, size_t user_data_size); +LL_GRAB_SYM(G, true, pw_context_destroy, void, struct pw_context *context); +LL_GRAB_SYM(G, true, pw_context_connect, struct pw_core *, struct pw_context *context, struct pw_properties *properties, size_t user_data_size); +LL_GRAB_SYM(G, true, pw_thread_loop_new, struct pw_thread_loop *, const char *name, const struct spa_dict *props); +LL_GRAB_SYM(G, true, pw_thread_loop_destroy, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_get_loop, struct pw_loop *, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_start, int, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_stop, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_lock, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_unlock, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_proxy_add_listener, void, struct pw_proxy *proxy, struct spa_hook *listener, const struct pw_proxy_events *events, void *data); +LL_GRAB_SYM(G, true, pw_proxy_destroy, void, struct pw_proxy *proxy); +LL_GRAB_SYM(G, true, pw_proxy_get_user_data, void *, struct pw_proxy *proxy); +LL_GRAB_SYM(G, true, pw_core_disconnect, int, struct pw_core *core); + +// optional symbols to grab + +#undef G diff --git a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp new file mode 100755 index 00000000000..f8a48a91fd7 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp @@ -0,0 +1,322 @@ +/** + * @file volume_catcher_pulseaudio.cpp + * @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * @endcond + */ + +/* + The high-level design is as follows: + 1) Connect to the PulseAudio daemon + 2) Watch for the creation of new audio players connecting to the daemon (this includes ALSA clients running on the PulseAudio emulation layer, such as Flash plugins) + 3) Examine any new audio player's PID to see if it belongs to our own process + 4) If so, tell PA to adjust the volume of that audio player ('sink input' in PA parlance) + 5) Keep a list of all living audio players that we care about, adjust the volumes of all of them when we get a new setVolume() call + */ + +#include "linden_common.h" + +#include "volume_catcher_linux.h" + +extern "C" { +#include +#include + +#include + +#include +} + +SymbolGrabber paSymbolGrabber; + +#include "volume_catcher_pulseaudio_syms.inc" +#include "volume_catcher_pulseaudio_glib_syms.inc" + +//////////////////////////////////////////////////// + +// PulseAudio requires a chain of callbacks with C linkage +extern "C" { + void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata); + void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata); + void callback_context_state(pa_context *context, void *userdata); +} + +VolumeCatcherPulseAudio::VolumeCatcherPulseAudio() + : mDesiredVolume(0.0f), + mMainloop(nullptr), + mPAContext(nullptr), + mConnected(false), + mGotSyms(false) +{ + init(); +} + +VolumeCatcherPulseAudio::~VolumeCatcherPulseAudio() +{ + cleanup(); +} + +bool VolumeCatcherPulseAudio::loadsyms(std::string pulse_dso_name) +{ + return paSymbolGrabber.grabSymbols({ pulse_dso_name }); +} + +void VolumeCatcherPulseAudio::init() +{ + // try to be as defensive as possible because PA's interface is a + // bit fragile and (for our purposes) we'd rather simply not function + // than crash + + // we cheat and rely upon libpulse-mainloop-glib.so.0 to pull-in + // libpulse.so.0 - this isn't a great assumption, and the two DSOs should + // probably be loaded separately. Our Linux DSO framework needs refactoring, + // we do this sort of thing a lot with practically identical logic... + mGotSyms = loadsyms("libpulse-mainloop-glib.so.0"); + + if (!mGotSyms) + mGotSyms = loadsyms("libpulse.so.0"); + + if (!mGotSyms) + return; + + mMainloop = llpa_glib_mainloop_new(g_main_context_default()); + + if (mMainloop) + { + pa_mainloop_api *api = llpa_glib_mainloop_get_api(mMainloop); + + if (api) + { + pa_proplist *proplist = llpa_proplist_new(); + + if (proplist) + { + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-player"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.secondlife.viewer.mediaplugvoladjust"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "SL Plugin Volume Adjuster"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, "1"); + + // plain old pa_context_new() is broken! + mPAContext = llpa_context_new_with_proplist(api, nullptr, proplist); + + llpa_proplist_free(proplist); + } + } + } + + // Now we've set up a PA context and mainloop, try connecting the + // PA context to a PA daemon. + if (mPAContext) + { + llpa_context_set_state_callback(mPAContext, callback_context_state, this); + pa_context_flags_t cflags = (pa_context_flags)0; // maybe add PA_CONTEXT_NOAUTOSPAWN? + if (llpa_context_connect(mPAContext, nullptr, cflags, nullptr) >= 0) + { + // Okay! We haven't definitely connected, but we + // haven't definitely failed yet. + } + else + { + // Failed to connect to PA manager... we'll leave + // things like that. Perhaps we should try again later. + } + } +} + +void VolumeCatcherPulseAudio::cleanup() +{ + mConnected = false; + + if (mGotSyms && mPAContext) + { + llpa_context_disconnect(mPAContext); + llpa_context_unref(mPAContext); + } + + mPAContext = nullptr; + + if (mGotSyms && mMainloop) + llpa_glib_mainloop_free(mMainloop); + + mMainloop = nullptr; +} + +void VolumeCatcherPulseAudio::setVolume(F32 volume) +{ + mDesiredVolume = volume; + + if (!mGotSyms) + return; + + if (mConnected && mPAContext) + { + update_all_volumes(mDesiredVolume); + } + + pump(); +} + +void VolumeCatcherPulseAudio::setPan(F32 pan) +{ +} + +void VolumeCatcherPulseAudio::pump() +{ + gboolean may_block = FALSE; + g_main_context_iteration(g_main_context_default(), may_block); +} + +void VolumeCatcherPulseAudio::connected_okay() +{ + pa_operation *op; + + // fetch global list of existing sinkinputs + if ((op = llpa_context_get_sink_input_info_list(mPAContext, + callback_discovered_sinkinput, + this))) + { + llpa_operation_unref(op); + } + + // subscribe to future global sinkinput changes + llpa_context_set_subscribe_callback(mPAContext, + callback_subscription_alert, + this); + if ((op = llpa_context_subscribe(mPAContext, (pa_subscription_mask_t) + (PA_SUBSCRIPTION_MASK_SINK_INPUT), + nullptr, nullptr))) + { + llpa_operation_unref(op); + } +} + +void VolumeCatcherPulseAudio::update_all_volumes(F32 volume) +{ + for (std::set::iterator it = mSinkInputIndices.begin(); + it != mSinkInputIndices.end(); ++it) + { + update_index_volume(*it, volume); + } +} + +void VolumeCatcherPulseAudio::update_index_volume(U32 index, F32 volume) +{ + static pa_cvolume cvol; + llpa_cvolume_set(&cvol, mSinkInputNumChannels[index], + llpa_sw_volume_from_linear(volume)); + + pa_context *c = mPAContext; + uint32_t idx = index; + const pa_cvolume *cvolumep = &cvol; + pa_context_success_cb_t cb = nullptr; // okay as null + void *userdata = nullptr; // okay as null + + pa_operation *op; + if ((op = llpa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata))) + llpa_operation_unref(op); +} + +void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata) +{ + VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); + llassert(impl); + + if (0 == eol) + { + pa_proplist *proplist = sii->proplist; + pid_t sinkpid = atoll(llpa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID)); + + if (isPluginPid( sinkpid )) // does the discovered sinkinput belong to this process? + { + bool is_new = (impl->mSinkInputIndices.find(sii->index) == impl->mSinkInputIndices.end()); + + impl->mSinkInputIndices.insert(sii->index); + impl->mSinkInputNumChannels[sii->index] = sii->channel_map.channels; + + if (is_new) + { + // new! + impl->update_index_volume(sii->index, impl->mDesiredVolume); + } + else + { + // seen it already, do nothing. + } + } + } +} + +void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata) +{ + VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); + llassert(impl); + + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) + { + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) + { + // forget this sinkinput, if we were caring about it + impl->mSinkInputIndices.erase(index); + impl->mSinkInputNumChannels.erase(index); + } + else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) + { + // ask for more info about this new sinkinput + pa_operation *op; + if ((op = llpa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl))) + { + llpa_operation_unref(op); + } + } + else + { + // property change on this sinkinput - we don't care. + } + break; + + default:; + } +} + +void callback_context_state(pa_context *context, void *userdata) +{ + VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); + llassert(impl); + + switch (llpa_context_get_state(context)) + { + case PA_CONTEXT_READY: + impl->mConnected = true; + impl->connected_okay(); + break; + case PA_CONTEXT_TERMINATED: + impl->mConnected = false; + break; + case PA_CONTEXT_FAILED: + impl->mConnected = false; + break; + default:; + } +} diff --git a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_glib_syms.inc b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_glib_syms.inc new file mode 100755 index 00000000000..e9b7196e51b --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_glib_syms.inc @@ -0,0 +1,10 @@ +#define G paSymbolGrabber + +// required symbols to grab +LL_GRAB_SYM(G, true, pa_glib_mainloop_free, void, pa_glib_mainloop* g) +LL_GRAB_SYM(G, true, pa_glib_mainloop_get_api, pa_mainloop_api*, pa_glib_mainloop* g) +LL_GRAB_SYM(G, true, pa_glib_mainloop_new, pa_glib_mainloop *, GMainContext *c) + +// optional symbols to grab + +#undef G diff --git a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_syms.inc b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_syms.inc new file mode 100755 index 00000000000..4859a344054 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_syms.inc @@ -0,0 +1,29 @@ +#define G paSymbolGrabber + +// required symbols to grab +LL_GRAB_SYM(G, true, pa_context_connect, int, pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api) +LL_GRAB_SYM(G, true, pa_context_disconnect, void, pa_context *c) +LL_GRAB_SYM(G, true, pa_context_get_sink_input_info, pa_operation*, pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_get_sink_input_info_list, pa_operation*, pa_context *c, pa_sink_input_info_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_get_state, pa_context_state_t, pa_context *c) +LL_GRAB_SYM(G, true, pa_context_new_with_proplist, pa_context*, pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist) +LL_GRAB_SYM(G, true, pa_context_set_sink_input_volume, pa_operation*, pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_set_state_callback, void, pa_context *c, pa_context_notify_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_set_subscribe_callback, void, pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_subscribe, pa_operation*, pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_unref, void, pa_context *c) +LL_GRAB_SYM(G, true, pa_cvolume_set, pa_cvolume*, pa_cvolume *a, unsigned channels, pa_volume_t v) +LL_GRAB_SYM(G, true, pa_operation_unref, void, pa_operation *o) +LL_GRAB_SYM(G, true, pa_proplist_free, void, pa_proplist* p) +LL_GRAB_SYM(G, true, pa_proplist_gets, const char*, pa_proplist *p, const char *key) +LL_GRAB_SYM(G, true, pa_proplist_new, pa_proplist*, void) +LL_GRAB_SYM(G, true, pa_proplist_sets, int, pa_proplist *p, const char *key, const char *value) +LL_GRAB_SYM(G, true, pa_sw_volume_from_linear, pa_volume_t, double v) +// LL_GRAB_SYM(G, true, pa_mainloop_free, void, pa_mainloop *m) +// LL_GRAB_SYM(G, true, pa_mainloop_get_api, pa_mainloop_api *, pa_mainloop *m) +// LL_GRAB_SYM(G, true, pa_mainloop_iterate, int, pa_mainloop *m, int block, int *retval) +// LL_GRAB_SYM(G, true, pa_mainloop_new, pa_mainloop *, void) + +// optional symbols to grab + +#undef G diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index caf804f915d..434f1c78e8a 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -911,7 +911,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string) keyEvent(key_event, native_key_data); -#elif LL_WINDOWS +#else std::string event = message_in.getValue("event"); LLSD native_key_data = message_in.getValueLLSD("native_key_data"); @@ -933,6 +933,13 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { mEnableMediaPluginDebugging = message_in.getValueBoolean("enable"); } +#if LL_LINUX + else if (message_name == "enable_pipewire_volume_catcher") + { + bool enable = message_in.getValueBoolean("enable"); + mVolumeCatcher.onEnablePipeWireVolumeCatcher(enable); + } +#endif if (message_name == "pick_file_response") { LLSD file_list_llsd = message_in.getValueLLSD("file_list"); @@ -1095,6 +1102,28 @@ void MediaPluginCEF::keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_dat mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam); #endif + +#if LL_LINUX + + uint32_t native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); // this is actually the SDL event.key.keysym.sym; + uint32_t native_virtual_key_win = (uint32_t)(native_key_data["virtual_key_win"].asInteger()); + uint32_t native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); + + // only for non-printable keysyms, the actual text input is done in unicodeInput() below + if (native_virtual_key <= 0x1b || native_virtual_key >= 0x7f) + { + // set keypad flag, not sure if this even does anything + bool keypad = false; + if (native_virtual_key_win >= 0x60 && native_virtual_key_win <= 0x6f) + { + keypad = true; + } + + // yes, we send native_virtual_key_win twice because native_virtual_key breaks it + mCEFLib->nativeKeyboardEventSDL2(key_event, native_virtual_key_win, native_modifiers, keypad); + } + +#endif // LL_LINUX }; void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD::emptyMap()) @@ -1125,6 +1154,16 @@ void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD U64 lparam = ll_U32_from_sd(native_key_data["l_param"]); mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam); #endif + +#if LL_LINUX + + uint32_t native_scan_code = (uint32_t)(native_key_data["sdl_sym"].asInteger()); + uint32_t native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); + uint32_t native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); + + mCEFLib->nativeKeyboardEvent(dullahan::KE_KEY_DOWN, native_scan_code, native_virtual_key, native_modifiers); + +#endif // LL_LINUX }; //////////////////////////////////////////////////////////////////////////////// diff --git a/indra/media_plugins/cef/volume_catcher.h b/indra/media_plugins/cef/volume_catcher.h index ea97a24947d..806f2a008a4 100644 --- a/indra/media_plugins/cef/volume_catcher.h +++ b/indra/media_plugins/cef/volume_catcher.h @@ -35,7 +35,7 @@ class VolumeCatcherImpl; class VolumeCatcher { - public: +public: VolumeCatcher(); ~VolumeCatcher(); @@ -47,8 +47,14 @@ class VolumeCatcher void pump(); // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume - private: +#if LL_LINUX + void onEnablePipeWireVolumeCatcher(bool enable); +#endif + +private: +#if LL_LINUX || LL_WINDOWS VolumeCatcherImpl *pimpl; +#endif }; #endif // VOLUME_CATCHER_H diff --git a/indra/media_plugins/cef/mac_volume_catcher_null.cpp b/indra/media_plugins/cef/volume_catcher_null.cpp similarity index 58% rename from indra/media_plugins/cef/mac_volume_catcher_null.cpp rename to indra/media_plugins/cef/volume_catcher_null.cpp index c479e24a954..1f0f1e8e38f 100644 --- a/indra/media_plugins/cef/mac_volume_catcher_null.cpp +++ b/indra/media_plugins/cef/volume_catcher_null.cpp @@ -1,5 +1,5 @@ /** - * @file windows_volume_catcher.cpp + * @file volume_catcher_null.cpp * @brief A null implementation of volume level control of all audio channels opened by a process. * We are using this for the macOS version for now until we can understand how to make the * exitising mac_volume_catcher.cpp work without the (now, non-existant) QuickTime dependency @@ -29,67 +29,25 @@ */ #include "volume_catcher.h" -#include "llsingleton.h" -class VolumeCatcherImpl : public LLSingleton -{ - LLSINGLETON(VolumeCatcherImpl); - // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance. - ~VolumeCatcherImpl(); - -public: - - void setVolume(F32 volume); - void setPan(F32 pan); - -private: - F32 mVolume; - F32 mPan; - bool mSystemIsVistaOrHigher; -}; - -VolumeCatcherImpl::VolumeCatcherImpl() -: mVolume(1.0f), // default volume is max - mPan(0.f) // default pan is centered -{ -} - -VolumeCatcherImpl::~VolumeCatcherImpl() -{ -} - -void VolumeCatcherImpl::setVolume(F32 volume) -{ - mVolume = volume; -} - -void VolumeCatcherImpl::setPan(F32 pan) -{ // remember pan for calculating individual channel levels later - mPan = pan; -} ///////////////////////////////////////////////////// VolumeCatcher::VolumeCatcher() { - pimpl = VolumeCatcherImpl::getInstance(); } VolumeCatcher::~VolumeCatcher() { - // Let the instance persist until exit. } void VolumeCatcher::setVolume(F32 volume) { - pimpl->setVolume(volume); } void VolumeCatcher::setPan(F32 pan) { - pimpl->setPan(pan); } void VolumeCatcher::pump() { - // No periodic tasks are necessary for this implementation. } diff --git a/indra/media_plugins/cef/windows_volume_catcher.cpp b/indra/media_plugins/cef/windows_volume_catcher.cpp index e7daeb5f748..1e52fee9ded 100644 --- a/indra/media_plugins/cef/windows_volume_catcher.cpp +++ b/indra/media_plugins/cef/windows_volume_catcher.cpp @@ -44,7 +44,6 @@ class VolumeCatcherImpl : public LLSingleton private: F32 mVolume; F32 mPan; - bool mSystemIsVistaOrHigher; }; VolumeCatcherImpl::VolumeCatcherImpl() diff --git a/indra/media_plugins/gstreamer010/CMakeLists.txt b/indra/media_plugins/gstreamer010/CMakeLists.txt deleted file mode 100644 index 38fc8201bf2..00000000000 --- a/indra/media_plugins/gstreamer010/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# -*- cmake -*- - -project(media_plugin_gstreamer010) - -include(00-Common) -include(LLCommon) -include(LLImage) -include(LLMath) -include(LLWindow) -include(Linking) -include(PluginAPI) -include(OpenGL) - -include(GStreamer010Plugin) - -### media_plugin_gstreamer010 - -if(NOT ADDRESS_SIZE EQUAL 32) - if(WINDOWS) - ##add_definitions(/FIXED:NO) - else(WINDOWS) # not windows therefore gcc LINUX and DARWIN - add_definitions(-fPIC) - endif(WINDOWS) -endif(NOT ADDRESS_SIZE EQUAL 32) - -set(media_plugin_gstreamer010_SOURCE_FILES - media_plugin_gstreamer010.cpp - llmediaimplgstreamer_syms.cpp - llmediaimplgstreamervidplug.cpp - ) - -set(media_plugin_gstreamer010_HEADER_FILES - llmediaimplgstreamervidplug.h - llmediaimplgstreamer_syms.h - llmediaimplgstreamertriviallogging.h - ) - -add_library(media_plugin_gstreamer010 - SHARED - ${media_plugin_gstreamer010_SOURCE_FILES} - ) - -target_link_libraries(media_plugin_gstreamer010 - media_plugin_base - ll::gstreamer - ) diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp deleted file mode 100644 index dcc04b37e43..00000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/** - * @file llmediaimplgstreamer_syms.cpp - * @brief dynamic GStreamer symbol-grabbing code - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#if LL_GSTREAMER010_ENABLED - -#include - -extern "C" { -#include - -#include "apr_pools.h" -#include "apr_dso.h" -} - -#include "llmediaimplgstreamertriviallogging.h" - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - -// a couple of stubs for disgusting reasons -GstDebugCategory* -ll_gst_debug_category_new(gchar *name, guint color, gchar *description) -{ - static GstDebugCategory dummy; - return &dummy; -} -void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname) -{ -} - -static bool sSymsGrabbed = false; -static apr_pool_t *sSymGSTDSOMemoryPool = NULL; -static apr_dso_handle_t *sSymGSTDSOHandleG = NULL; -static apr_dso_handle_t *sSymGSTDSOHandleV = NULL; - - -bool grab_gst_syms(std::string gst_dso_name, - std::string gst_dso_name_vid) -{ - if (sSymsGrabbed) - { - // already have grabbed good syms - return TRUE; - } - - bool sym_error = false; - bool rtn = false; - apr_status_t rv; - apr_dso_handle_t *sSymGSTDSOHandle = NULL; - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0) - - //attempt to load the shared libraries - apr_pool_create(&sSymGSTDSOMemoryPool, NULL); - - if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle, - gst_dso_name.c_str(), - sSymGSTDSOMemoryPool) )) - { - INFOMSG("Found DSO: %s", gst_dso_name.c_str()); -#include "llmediaimplgstreamer_syms_raw.inc" - - if ( sSymGSTDSOHandle ) - { - sSymGSTDSOHandleG = sSymGSTDSOHandle; - sSymGSTDSOHandle = NULL; - } - - if ( APR_SUCCESS == - (rv = apr_dso_load(&sSymGSTDSOHandle, - gst_dso_name_vid.c_str(), - sSymGSTDSOMemoryPool) )) - { - INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str()); -#include "llmediaimplgstreamer_syms_rawv.inc" - rtn = !sym_error; - } - else - { - INFOMSG("Couldn't load DSO: %s", gst_dso_name_vid.c_str()); - rtn = false; // failure - } - } - else - { - INFOMSG("Couldn't load DSO: %s", gst_dso_name.c_str()); - rtn = false; // failure - } - - if (sym_error) - { - WARNMSG("Failed to find necessary symbols in GStreamer libraries."); - } - - if ( sSymGSTDSOHandle ) - { - sSymGSTDSOHandleV = sSymGSTDSOHandle; - sSymGSTDSOHandle = NULL; - } -#undef LL_GST_SYM - - sSymsGrabbed = !!rtn; - return rtn; -} - - -void ungrab_gst_syms() -{ - // should be safe to call regardless of whether we've - // actually grabbed syms. - - if ( sSymGSTDSOHandleG ) - { - apr_dso_unload(sSymGSTDSOHandleG); - sSymGSTDSOHandleG = NULL; - } - - if ( sSymGSTDSOHandleV ) - { - apr_dso_unload(sSymGSTDSOHandleV); - sSymGSTDSOHandleV = NULL; - } - - if ( sSymGSTDSOMemoryPool ) - { - apr_pool_destroy(sSymGSTDSOMemoryPool); - sSymGSTDSOMemoryPool = NULL; - } - - // NULL-out all of the symbols we'd grabbed -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{ll##GSTSYM = NULL;}while(0) -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - - sSymsGrabbed = false; -} - - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h deleted file mode 100644 index 57d446c7dfd..00000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file llmediaimplgstreamer_syms.h - * @brief dynamic GStreamer symbol-grabbing code - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#include "linden_common.h" - -#if LL_GSTREAMER010_ENABLED - -extern "C" { -#include -} - -bool grab_gst_syms(std::string gst_dso_name, - std::string gst_dso_name_vid); -void ungrab_gst_syms(); - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__) -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - -// regrettable hacks to give us better runtime compatibility with older systems -#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0) -#define llg_return_val_if_fail(COND,V) do{if (!(COND)) return V;}while(0) - -// regrettable hacks because GStreamer was not designed for runtime loading -#undef GST_TYPE_MESSAGE -#define GST_TYPE_MESSAGE (llgst_message_get_type()) -#undef GST_TYPE_OBJECT -#define GST_TYPE_OBJECT (llgst_object_get_type()) -#undef GST_TYPE_PIPELINE -#define GST_TYPE_PIPELINE (llgst_pipeline_get_type()) -#undef GST_TYPE_ELEMENT -#define GST_TYPE_ELEMENT (llgst_element_get_type()) -#undef GST_TYPE_VIDEO_SINK -#define GST_TYPE_VIDEO_SINK (llgst_video_sink_get_type()) -// more regrettable hacks to stub-out these .h-exposed GStreamer internals -void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname); -#undef _gst_debug_register_funcptr -#define _gst_debug_register_funcptr ll_gst_debug_register_funcptr -GstDebugCategory* ll_gst_debug_category_new(gchar *name, guint color, gchar *description); -#undef _gst_debug_category_new -#define _gst_debug_category_new ll_gst_debug_category_new -#undef __gst_debug_enabled -#define __gst_debug_enabled (0) - -// more hacks -#define LLGST_MESSAGE_TYPE_NAME(M) (llgst_message_type_get_name(GST_MESSAGE_TYPE(M))) - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc deleted file mode 100644 index b33e59363d2..00000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc +++ /dev/null @@ -1,51 +0,0 @@ - -// required symbols to grab -LL_GST_SYM(true, gst_pad_peer_accept_caps, gboolean, GstPad *pad, GstCaps *caps); -LL_GST_SYM(true, gst_buffer_new, GstBuffer*, void); -LL_GST_SYM(true, gst_buffer_set_caps, void, GstBuffer*, GstCaps *); -LL_GST_SYM(true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*); -LL_GST_SYM(true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err); -LL_GST_SYM(true, gst_message_get_type, GType, void); -LL_GST_SYM(true, gst_message_type_get_name, const gchar*, GstMessageType type); -LL_GST_SYM(true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending); -LL_GST_SYM(true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state); -LL_GST_SYM(true, gst_object_unref, void, gpointer object); -LL_GST_SYM(true, gst_object_get_type, GType, void); -LL_GST_SYM(true, gst_pipeline_get_type, GType, void); -LL_GST_SYM(true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline); -LL_GST_SYM(true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data); -LL_GST_SYM(true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name); -LL_GST_SYM(true, gst_element_get_type, GType, void); -LL_GST_SYM(true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template); -LL_GST_SYM(true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp); -LL_GST_SYM(true, gst_element_class_set_details, void, GstElementClass *klass, const GstElementDetails *details); -LL_GST_SYM(true, gst_caps_unref, void, GstCaps* caps); -LL_GST_SYM(true, gst_caps_ref, GstCaps *, GstCaps* caps); -//LL_GST_SYM(true, gst_caps_is_empty, gboolean, const GstCaps *caps); -LL_GST_SYM(true, gst_caps_from_string, GstCaps *, const gchar *string); -LL_GST_SYM(true, gst_caps_replace, void, GstCaps **caps, GstCaps *newcaps); -LL_GST_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index); -LL_GST_SYM(true, gst_caps_copy, GstCaps *, const GstCaps * caps); -//LL_GST_SYM(true, gst_caps_intersect, GstCaps *, const GstCaps *caps1, const GstCaps *caps2); -LL_GST_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type); -LL_GST_SYM(true, _gst_plugin_register_static, void, GstPluginDesc *desc); -LL_GST_SYM(true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value); -LL_GST_SYM(true, gst_structure_get_value, G_CONST_RETURN GValue *, const GstStructure *structure, const gchar *fieldname); -LL_GST_SYM(true, gst_value_get_fraction_numerator, gint, const GValue *value); -LL_GST_SYM(true, gst_value_get_fraction_denominator, gint, const GValue *value); -LL_GST_SYM(true, gst_structure_get_name, G_CONST_RETURN gchar *, const GstStructure *structure); -LL_GST_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64); - -// optional symbols to grab -LL_GST_SYM(false, gst_registry_fork_set_enabled, void, gboolean enabled); -LL_GST_SYM(false, gst_segtrap_set_enabled, void, gboolean enabled); -LL_GST_SYM(false, gst_message_parse_buffering, void, GstMessage *message, gint *percent); -LL_GST_SYM(false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur); -LL_GST_SYM(false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano); - -// GStreamer 'internal' symbols which may not be visible in some runtimes but are still used in expanded GStreamer header macros - yuck! We'll substitute our own stubs for these. -//LL_GST_SYM(true, _gst_debug_register_funcptr, void, GstDebugFuncPtr func, gchar* ptrname); -//LL_GST_SYM(true, _gst_debug_category_new, GstDebugCategory *, gchar *name, guint color, gchar *description); diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc deleted file mode 100644 index 14fbcb48b98..00000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc +++ /dev/null @@ -1,5 +0,0 @@ - -// required symbols to grab -LL_GST_SYM(true, gst_video_sink_get_type, GType, void); - -// optional symbols to grab diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h deleted file mode 100644 index 43ebad67441..00000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file llmediaimplgstreamertriviallogging.h - * @brief minimal logging utilities. - * - * @cond - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#ifndef __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ -#define __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ - -#include - -extern "C" { -#include -#include -} - -///////////////////////////////////////////////////////////////////////// -// Debug/Info/Warning macros. -#define MSGMODULEFOO "(media plugin)" -#define STDERRMSG(...) do{\ - fprintf(stderr, " pid:%d: ", (int)getpid());\ - fprintf(stderr, MSGMODULEFOO " %s:%d: ", __FUNCTION__, __LINE__);\ - fprintf(stderr, __VA_ARGS__);\ - fputc('\n',stderr);\ - }while(0) -#define NULLMSG(...) do{}while(0) - -#define DEBUGMSG NULLMSG -#define INFOMSG STDERRMSG -#define WARNMSG STDERRMSG -///////////////////////////////////////////////////////////////////////// - -#endif /* __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ */ diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp deleted file mode 100644 index acec0f23992..00000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp +++ /dev/null @@ -1,526 +0,0 @@ -/** - * @file llmediaimplgstreamervidplug.h - * @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#if LL_GSTREAMER010_ENABLED - -#include "linden_common.h" - -#include -#include -#include - -#include "llmediaimplgstreamer_syms.h" -#include "llmediaimplgstreamertriviallogging.h" - -#include "llmediaimplgstreamervidplug.h" - - -GST_DEBUG_CATEGORY_STATIC (gst_slvideo_debug); -#define GST_CAT_DEFAULT gst_slvideo_debug - - -#define SLV_SIZECAPS ", width=(int)[1,2048], height=(int)[1,2048] " -#define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS - -static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( - (gchar*)"sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (SLV_ALLCAPS) - ); - -GST_BOILERPLATE (GstSLVideo, gst_slvideo, GstVideoSink, - GST_TYPE_VIDEO_SINK); - -static void gst_slvideo_set_property (GObject * object, guint prop_id, - const GValue * value, - GParamSpec * pspec); -static void gst_slvideo_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static void -gst_slvideo_base_init (gpointer gclass) -{ - static GstElementDetails element_details = { - (gchar*)"PluginTemplate", - (gchar*)"Generic/PluginTemplate", - (gchar*)"Generic Template Element", - (gchar*)"Linden Lab" - }; - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - - llgst_element_class_add_pad_template (element_class, - llgst_static_pad_template_get (&sink_factory)); - llgst_element_class_set_details (element_class, &element_details); -} - - -static void -gst_slvideo_finalize (GObject * object) -{ - GstSLVideo *slvideo; - slvideo = GST_SLVIDEO (object); - if (slvideo->caps) - { - llgst_caps_unref(slvideo->caps); - } - - G_OBJECT_CLASS(parent_class)->finalize (object); -} - - -static GstFlowReturn -gst_slvideo_show_frame (GstBaseSink * bsink, GstBuffer * buf) -{ - GstSLVideo *slvideo; - llg_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); - - slvideo = GST_SLVIDEO(bsink); - - DEBUGMSG("transferring a frame of %dx%d <- %p (%d)", - slvideo->width, slvideo->height, GST_BUFFER_DATA(buf), - slvideo->format); - - if (GST_BUFFER_DATA(buf)) - { - // copy frame and frame info into neutral territory - GST_OBJECT_LOCK(slvideo); - slvideo->retained_frame_ready = TRUE; - slvideo->retained_frame_width = slvideo->width; - slvideo->retained_frame_height = slvideo->height; - slvideo->retained_frame_format = slvideo->format; - int rowbytes = - SLVPixelFormatBytes[slvideo->retained_frame_format] * - slvideo->retained_frame_width; - int needbytes = rowbytes * slvideo->retained_frame_width; - // resize retained frame hunk only if necessary - if (needbytes != slvideo->retained_frame_allocbytes) - { - delete[] slvideo->retained_frame_data; - slvideo->retained_frame_data = new unsigned char[needbytes]; - slvideo->retained_frame_allocbytes = needbytes; - - } - // copy the actual frame data to neutral territory - - // flipped, for GL reasons - for (int ypos=0; yposheight; ++ypos) - { - memcpy(&slvideo->retained_frame_data[(slvideo->height-1-ypos)*rowbytes], - &(((unsigned char*)GST_BUFFER_DATA(buf))[ypos*rowbytes]), - rowbytes); - } - // done with the shared data - GST_OBJECT_UNLOCK(slvideo); - } - - return GST_FLOW_OK; -} - - -static GstStateChangeReturn -gst_slvideo_change_state(GstElement * element, GstStateChange transition) -{ - GstSLVideo *slvideo; - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - - slvideo = GST_SLVIDEO (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - slvideo->fps_n = 0; - slvideo->fps_d = 1; - GST_VIDEO_SINK_WIDTH(slvideo) = 0; - GST_VIDEO_SINK_HEIGHT(slvideo) = 0; - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - - -static GstCaps * -gst_slvideo_get_caps (GstBaseSink * bsink) -{ - GstSLVideo *slvideo; - slvideo = GST_SLVIDEO(bsink); - - return llgst_caps_ref (slvideo->caps); -} - - -/* this function handles the link with other elements */ -static gboolean -gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps) -{ - GstSLVideo *filter; - GstStructure *structure; - - GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); - - filter = GST_SLVIDEO(bsink); - - int width, height; - gboolean ret; - const GValue *fps; - const GValue *par; - structure = llgst_caps_get_structure (caps, 0); - ret = llgst_structure_get_int (structure, "width", &width); - ret = ret && llgst_structure_get_int (structure, "height", &height); - fps = llgst_structure_get_value (structure, "framerate"); - ret = ret && (fps != NULL); - par = llgst_structure_get_value (structure, "pixel-aspect-ratio"); - if (!ret) - return FALSE; - - INFOMSG("** filter caps set with width=%d, height=%d", width, height); - - GST_OBJECT_LOCK(filter); - - filter->width = width; - filter->height = height; - - filter->fps_n = llgst_value_get_fraction_numerator(fps); - filter->fps_d = llgst_value_get_fraction_denominator(fps); - if (par) - { - filter->par_n = llgst_value_get_fraction_numerator(par); - filter->par_d = llgst_value_get_fraction_denominator(par); - } - else - { - filter->par_n = 1; - filter->par_d = 1; - } - GST_VIDEO_SINK_WIDTH(filter) = width; - GST_VIDEO_SINK_HEIGHT(filter) = height; - - // crufty lump - we *always* accept *only* RGBX now. - /* - filter->format = SLV_PF_UNKNOWN; - if (0 == strcmp(llgst_structure_get_name(structure), - "video/x-raw-rgb")) - { - int red_mask; - int green_mask; - int blue_mask; - llgst_structure_get_int(structure, "red_mask", &red_mask); - llgst_structure_get_int(structure, "green_mask", &green_mask); - llgst_structure_get_int(structure, "blue_mask", &blue_mask); - if ((unsigned int)red_mask == 0xFF000000 && - (unsigned int)green_mask == 0x00FF0000 && - (unsigned int)blue_mask == 0x0000FF00) - { - filter->format = SLV_PF_RGBX; - //fprintf(stderr, "\n\nPIXEL FORMAT RGB\n\n"); - } else if ((unsigned int)red_mask == 0x0000FF00 && - (unsigned int)green_mask == 0x00FF0000 && - (unsigned int)blue_mask == 0xFF000000) - { - filter->format = SLV_PF_BGRX; - //fprintf(stderr, "\n\nPIXEL FORMAT BGR\n\n"); - } - }*/ - - filter->format = SLV_PF_RGBX; - - GST_OBJECT_UNLOCK(filter); - - return TRUE; -} - - -static gboolean -gst_slvideo_start (GstBaseSink * bsink) -{ - gboolean ret = TRUE; - - GST_SLVIDEO(bsink); - - return ret; -} - -static gboolean -gst_slvideo_stop (GstBaseSink * bsink) -{ - GstSLVideo *slvideo; - slvideo = GST_SLVIDEO(bsink); - - // free-up retained frame buffer - GST_OBJECT_LOCK(slvideo); - slvideo->retained_frame_ready = FALSE; - delete[] slvideo->retained_frame_data; - slvideo->retained_frame_data = NULL; - slvideo->retained_frame_allocbytes = 0; - GST_OBJECT_UNLOCK(slvideo); - - return TRUE; -} - - -static GstFlowReturn -gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, - GstCaps * caps, GstBuffer ** buf) -{ - gint width, height; - GstStructure *structure = NULL; - GstSLVideo *slvideo; - slvideo = GST_SLVIDEO(bsink); - - // caps == requested caps - // we can ignore these and reverse-negotiate our preferred dimensions with - // the peer if we like - we need to do this to obey dynamic resize requests - // flowing in from the app. - structure = llgst_caps_get_structure (caps, 0); - if (!llgst_structure_get_int(structure, "width", &width) || - !llgst_structure_get_int(structure, "height", &height)) - { - GST_WARNING_OBJECT (slvideo, "no width/height in caps %" GST_PTR_FORMAT, caps); - return GST_FLOW_NOT_NEGOTIATED; - } - - GstBuffer *newbuf = llgst_buffer_new(); - bool made_bufferdata_ptr = false; -#define MAXDEPTHHACK 4 - - GST_OBJECT_LOCK(slvideo); - if (slvideo->resize_forced_always) // app is giving us a fixed size to work with - { - gint slwantwidth, slwantheight; - slwantwidth = slvideo->resize_try_width; - slwantheight = slvideo->resize_try_height; - - if (slwantwidth != width || - slwantheight != height) - { - // don't like requested caps, we will issue our own suggestion - copy - // the requested caps but substitute our own width and height and see - // if our peer is happy with that. - - GstCaps *desired_caps; - GstStructure *desired_struct; - desired_caps = llgst_caps_copy (caps); - desired_struct = llgst_caps_get_structure (desired_caps, 0); - - GValue value = {0}; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, slwantwidth); - llgst_structure_set_value (desired_struct, "width", &value); - g_value_unset(&value); - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, slwantheight); - llgst_structure_set_value (desired_struct, "height", &value); - - if (llgst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo), - desired_caps)) - { - // todo: re-use buffers from a pool? - // todo: set MALLOCDATA to null, set DATA to point straight to shm? - - // peer likes our cap suggestion - DEBUGMSG("peer loves us :)"); - GST_BUFFER_SIZE(newbuf) = slwantwidth * slwantheight * MAXDEPTHHACK; - GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); - GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); - llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps); - - made_bufferdata_ptr = true; - } else { - // peer hates our cap suggestion - INFOMSG("peer hates us :("); - llgst_caps_unref(desired_caps); - } - } - } - - GST_OBJECT_UNLOCK(slvideo); - - if (!made_bufferdata_ptr) // need to fallback to malloc at original size - { - GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK; - GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); - GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); - llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps); - } - - *buf = GST_BUFFER_CAST(newbuf); - - return GST_FLOW_OK; -} - - -/* initialize the plugin's class */ -static void -gst_slvideo_class_init (GstSLVideoClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - - gobject_class->finalize = gst_slvideo_finalize; - gobject_class->set_property = gst_slvideo_set_property; - gobject_class->get_property = gst_slvideo_get_property; - - gstelement_class->change_state = gst_slvideo_change_state; - -#define LLGST_DEBUG_FUNCPTR(p) (p) - gstbasesink_class->get_caps = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_caps); - gstbasesink_class->set_caps = LLGST_DEBUG_FUNCPTR( gst_slvideo_set_caps); - gstbasesink_class->buffer_alloc=LLGST_DEBUG_FUNCPTR(gst_slvideo_buffer_alloc); - //gstbasesink_class->get_times = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_times); - gstbasesink_class->preroll = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame); - gstbasesink_class->render = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame); - - gstbasesink_class->start = LLGST_DEBUG_FUNCPTR (gst_slvideo_start); - gstbasesink_class->stop = LLGST_DEBUG_FUNCPTR (gst_slvideo_stop); - - // gstbasesink_class->unlock = LLGST_DEBUG_FUNCPTR (gst_slvideo_unlock); -#undef LLGST_DEBUG_FUNCPTR -} - - -/* initialize the new element - * instantiate pads and add them to element - * set functions - * initialize structure - */ -static void -gst_slvideo_init (GstSLVideo * filter, - GstSLVideoClass * gclass) -{ - filter->caps = NULL; - filter->width = -1; - filter->height = -1; - - // this is the info we share with the client app - GST_OBJECT_LOCK(filter); - filter->retained_frame_ready = FALSE; - filter->retained_frame_data = NULL; - filter->retained_frame_allocbytes = 0; - filter->retained_frame_width = filter->width; - filter->retained_frame_height = filter->height; - filter->retained_frame_format = SLV_PF_UNKNOWN; - GstCaps *caps = llgst_caps_from_string (SLV_ALLCAPS); - llgst_caps_replace (&filter->caps, caps); - filter->resize_forced_always = false; - filter->resize_try_width = -1; - filter->resize_try_height = -1; - GST_OBJECT_UNLOCK(filter); -} - -static void -gst_slvideo_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - llg_return_if_fail (GST_IS_SLVIDEO (object)); - - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_slvideo_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - llg_return_if_fail (GST_IS_SLVIDEO (object)); - - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -/* entry point to initialize the plug-in - * initialize the plug-in itself - * register the element factories and pad templates - * register the features - */ -static gboolean -plugin_init (GstPlugin * plugin) -{ - DEBUGMSG("PLUGIN INIT"); - - GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, (gchar*)"private-slvideo-plugin", - 0, (gchar*)"Second Life Video Sink"); - - return llgst_element_register (plugin, "private-slvideo", - GST_RANK_NONE, GST_TYPE_SLVIDEO); -} - -/* this is the structure that gstreamer looks for to register plugins - */ -/* NOTE: Can't rely upon GST_PLUGIN_DEFINE_STATIC to self-register, since - some g++ versions buggily avoid __attribute__((constructor)) functions - - so we provide an explicit plugin init function. - */ -#define PACKAGE (gchar*)"packagehack" -// this macro quietly refers to PACKAGE internally -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - (gchar*)"private-slvideoplugin", - (gchar*)"SL Video sink plugin", - plugin_init, (gchar*)"1.0", (gchar*)"LGPL", - (gchar*)"Second Life", - (gchar*)"http://www.secondlife.com/"); -#undef PACKAGE -void gst_slvideo_init_class (void) -{ - ll_gst_plugin_register_static (&gst_plugin_desc); - DEBUGMSG("CLASS INIT"); -} - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h deleted file mode 100644 index d4e07daf4f1..00000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @file llmediaimplgstreamervidplug.h - * @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#ifndef __GST_SLVIDEO_H__ -#define __GST_SLVIDEO_H__ - -#if LL_GSTREAMER010_ENABLED - -extern "C" { -#include -#include -#include -} - -G_BEGIN_DECLS - -/* #defines don't like whitespacey bits */ -#define GST_TYPE_SLVIDEO \ - (gst_slvideo_get_type()) -#define GST_SLVIDEO(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SLVIDEO,GstSLVideo)) -#define GST_SLVIDEO_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SLVIDEO,GstSLVideoClass)) -#define GST_IS_SLVIDEO(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SLVIDEO)) -#define GST_IS_SLVIDEO_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SLVIDEO)) - -typedef struct _GstSLVideo GstSLVideo; -typedef struct _GstSLVideoClass GstSLVideoClass; - -typedef enum { - SLV_PF_UNKNOWN = 0, - SLV_PF_RGBX = 1, - SLV_PF_BGRX = 2, - SLV__END = 3 -} SLVPixelFormat; -const int SLVPixelFormatBytes[SLV__END] = {1, 4, 4}; - -struct _GstSLVideo -{ - GstVideoSink video_sink; - - GstCaps *caps; - - int fps_n, fps_d; - int par_n, par_d; - int height, width; - SLVPixelFormat format; - - // SHARED WITH APPLICATION: - // Access to the following should be protected by GST_OBJECT_LOCK() on - // the GstSLVideo object, and should be totally consistent upon UNLOCK - // (i.e. all written at once to reflect the current retained frame info - // when the retained frame is updated.) - bool retained_frame_ready; // new frame ready since flag last reset. (*TODO: could get the writer to wait on a semaphore instead of having the reader poll, potentially making dropped frames somewhat cheaper.) - unsigned char* retained_frame_data; - int retained_frame_allocbytes; - int retained_frame_width, retained_frame_height; - SLVPixelFormat retained_frame_format; - // sticky resize info - bool resize_forced_always; - int resize_try_width; - int resize_try_height; -}; - -struct _GstSLVideoClass -{ - GstVideoSinkClass parent_class; -}; - -GType gst_slvideo_get_type (void); - -void gst_slvideo_init_class (void); - -G_END_DECLS - -#endif // LL_GSTREAMER010_ENABLED - -#endif /* __GST_SLVIDEO_H__ */ diff --git a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp deleted file mode 100644 index 97d1d7d7b52..00000000000 --- a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp +++ /dev/null @@ -1,1266 +0,0 @@ -/** - * @file media_plugin_gstreamer010.cpp - * @brief GStreamer-0.10 plugin for LLMedia API plugin system - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#include "linden_common.h" - -#include "llgl.h" - -#include "llplugininstance.h" -#include "llpluginmessage.h" -#include "llpluginmessageclasses.h" -#include "media_plugin_base.h" - -#if LL_GSTREAMER010_ENABLED - -extern "C" { -#include -} - -#include "llmediaimplgstreamer.h" -#include "llmediaimplgstreamertriviallogging.h" - -#include "llmediaimplgstreamervidplug.h" - -#include "llmediaimplgstreamer_syms.h" - -////////////////////////////////////////////////////////////////////////////// -// -class MediaPluginGStreamer010 : public MediaPluginBase -{ -public: - MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); - ~MediaPluginGStreamer010(); - - /* virtual */ void receiveMessage(const char *message_string); - - static bool startup(); - static bool closedown(); - - gboolean processGSTEvents(GstBus *bus, - GstMessage *message); - -private: - std::string getVersion(); - bool navigateTo( const std::string urlIn ); - bool seek( double time_sec ); - bool setVolume( float volume ); - - // misc - bool pause(); - bool stop(); - bool play(double rate); - bool getTimePos(double &sec_out); - - static const double MIN_LOOP_SEC = 1.0F; - - bool mIsLooping; - - enum ECommand { - COMMAND_NONE, - COMMAND_STOP, - COMMAND_PLAY, - COMMAND_FAST_FORWARD, - COMMAND_FAST_REWIND, - COMMAND_PAUSE, - COMMAND_SEEK, - }; - ECommand mCommand; - -private: - bool unload(); - bool load(); - - bool update(int milliseconds); - void mouseDown( int x, int y ); - void mouseUp( int x, int y ); - void mouseMove( int x, int y ); - - void sizeChanged(); - - static bool mDoneInit; - - guint mBusWatchID; - - float mVolume; - - int mDepth; - - // media NATURAL size - int mNaturalWidth; - int mNaturalHeight; - // media current size - int mCurrentWidth; - int mCurrentHeight; - int mCurrentRowbytes; - // previous media size so we can detect changes - int mPreviousWidth; - int mPreviousHeight; - // desired render size from host - int mWidth; - int mHeight; - // padded texture size we need to write into - int mTextureWidth; - int mTextureHeight; - - int mTextureFormatPrimary; - int mTextureFormatType; - - bool mSeekWanted; - double mSeekDestination; - - // Very GStreamer-specific - GMainLoop *mPump; // event pump for this media - GstElement *mPlaybin; - GstElement *mVisualizer; - GstSLVideo *mVideoSink; -}; - -//static -bool MediaPluginGStreamer010::mDoneInit = false; - -MediaPluginGStreamer010::MediaPluginGStreamer010( - LLPluginInstance::sendMessageFunction host_send_func, - void *host_user_data ) : - MediaPluginBase(host_send_func, host_user_data), - mBusWatchID ( 0 ), - mCurrentRowbytes ( 4 ), - mTextureFormatPrimary ( GL_RGBA ), - mTextureFormatType ( GL_UNSIGNED_INT_8_8_8_8_REV ), - mSeekWanted(false), - mSeekDestination(0.0), - mPump ( NULL ), - mPlaybin ( NULL ), - mVisualizer ( NULL ), - mVideoSink ( NULL ), - mCommand ( COMMAND_NONE ) -{ - std::ostringstream str; - INFOMSG("MediaPluginGStreamer010 constructor - my PID=%u", U32(getpid())); -} - -/////////////////////////////////////////////////////////////////////////////// -// -//#define LL_GST_REPORT_STATE_CHANGES -#ifdef LL_GST_REPORT_STATE_CHANGES -static char* get_gst_state_name(GstState state) -{ - switch (state) { - case GST_STATE_VOID_PENDING: return "VOID_PENDING"; - case GST_STATE_NULL: return "NULL"; - case GST_STATE_READY: return "READY"; - case GST_STATE_PAUSED: return "PAUSED"; - case GST_STATE_PLAYING: return "PLAYING"; - } - return "(unknown)"; -} -#endif // LL_GST_REPORT_STATE_CHANGES - -gboolean -MediaPluginGStreamer010::processGSTEvents(GstBus *bus, - GstMessage *message) -{ - if (!message) - return TRUE; // shield against GStreamer bug - - if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STATE_CHANGED && - GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING) - { - DEBUGMSG("Got GST message type: %s", - LLGST_MESSAGE_TYPE_NAME (message)); - } - else - { - // TODO: grok 'duration' message type - DEBUGMSG("Got GST message type: %s", - LLGST_MESSAGE_TYPE_NAME (message)); - } - - switch (GST_MESSAGE_TYPE (message)) { - case GST_MESSAGE_BUFFERING: { - // NEEDS GST 0.10.11+ - if (llgst_message_parse_buffering) - { - gint percent = 0; - llgst_message_parse_buffering(message, &percent); - DEBUGMSG("GST buffering: %d%%", percent); - } - break; - } - case GST_MESSAGE_STATE_CHANGED: { - GstState old_state; - GstState new_state; - GstState pending_state; - llgst_message_parse_state_changed(message, - &old_state, - &new_state, - &pending_state); -#ifdef LL_GST_REPORT_STATE_CHANGES - // not generally very useful, and rather spammy. - DEBUGMSG("state change (old,,pending): %s,<%s>,%s", - get_gst_state_name(old_state), - get_gst_state_name(new_state), - get_gst_state_name(pending_state)); -#endif // LL_GST_REPORT_STATE_CHANGES - - switch (new_state) { - case GST_STATE_VOID_PENDING: - break; - case GST_STATE_NULL: - break; - case GST_STATE_READY: - setStatus(STATUS_LOADED); - break; - case GST_STATE_PAUSED: - setStatus(STATUS_PAUSED); - break; - case GST_STATE_PLAYING: - setStatus(STATUS_PLAYING); - break; - } - break; - } - case GST_MESSAGE_ERROR: { - GError *err = NULL; - gchar *debug = NULL; - - llgst_message_parse_error (message, &err, &debug); - WARNMSG("GST error: %s", err?err->message:"(unknown)"); - if (err) - g_error_free (err); - g_free (debug); - - mCommand = COMMAND_STOP; - - setStatus(STATUS_ERROR); - - break; - } - case GST_MESSAGE_INFO: { - if (llgst_message_parse_info) - { - GError *err = NULL; - gchar *debug = NULL; - - llgst_message_parse_info (message, &err, &debug); - INFOMSG("GST info: %s", err?err->message:"(unknown)"); - if (err) - g_error_free (err); - g_free (debug); - } - break; - } - case GST_MESSAGE_WARNING: { - GError *err = NULL; - gchar *debug = NULL; - - llgst_message_parse_warning (message, &err, &debug); - WARNMSG("GST warning: %s", err?err->message:"(unknown)"); - if (err) - g_error_free (err); - g_free (debug); - - break; - } - case GST_MESSAGE_EOS: - /* end-of-stream */ - DEBUGMSG("GST end-of-stream."); - if (mIsLooping) - { - DEBUGMSG("looping media..."); - double eos_pos_sec = 0.0F; - bool got_eos_position = getTimePos(eos_pos_sec); - - if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC) - { - // if we know that the movie is really short, don't - // loop it else it can easily become a time-hog - // because of GStreamer spin-up overhead - DEBUGMSG("really short movie (%0.3fsec) - not gonna loop this, pausing instead.", eos_pos_sec); - // inject a COMMAND_PAUSE - mCommand = COMMAND_PAUSE; - } - else - { -#undef LLGST_LOOP_BY_SEEKING -// loop with a stop-start instead of a seek, because it actually seems rather -// faster than seeking on remote streams. -#ifdef LLGST_LOOP_BY_SEEKING - // first, try looping by an explicit rewind - bool seeksuccess = seek(0.0); - if (seeksuccess) - { - play(1.0); - } - else -#endif // LLGST_LOOP_BY_SEEKING - { // use clumsy stop-start to loop - DEBUGMSG("didn't loop by rewinding - stopping and starting instead..."); - stop(); - play(1.0); - } - } - } - else // not a looping media - { - // inject a COMMAND_STOP - mCommand = COMMAND_STOP; - } - break; - default: - /* unhandled message */ - break; - } - - /* we want to be notified again the next time there is a message - * on the bus, so return true (false means we want to stop watching - * for messages on the bus and our callback should not be called again) - */ - return TRUE; -} - -extern "C" { -gboolean -llmediaimplgstreamer_bus_callback (GstBus *bus, - GstMessage *message, - gpointer data) -{ - MediaPluginGStreamer010 *impl = (MediaPluginGStreamer010*)data; - return impl->processGSTEvents(bus, message); -} -} // extern "C" - - - -bool -MediaPluginGStreamer010::navigateTo ( const std::string urlIn ) -{ - if (!mDoneInit) - return false; // error - - setStatus(STATUS_LOADING); - - DEBUGMSG("Setting media URI: %s", urlIn.c_str()); - - mSeekWanted = false; - - if (NULL == mPump || - NULL == mPlaybin) - { - setStatus(STATUS_ERROR); - return false; // error - } - - // set URI - g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL); - //g_object_set (G_OBJECT (mPlaybin), "uri", "file:///tmp/movie", NULL); - - // navigateTo implicitly plays, too. - play(1.0); - - return true; -} - - -bool -MediaPluginGStreamer010::update(int milliseconds) -{ - if (!mDoneInit) - return false; // error - - DEBUGMSG("updating media..."); - - // sanity check - if (NULL == mPump || - NULL == mPlaybin) - { - DEBUGMSG("dead media..."); - return false; - } - - // see if there's an outstanding seek wanted - if (mSeekWanted && - // bleh, GST has to be happy that the movie is really truly playing - // or it may quietly ignore the seek (with rtsp:// at least). - (GST_STATE(mPlaybin) == GST_STATE_PLAYING)) - { - seek(mSeekDestination); - mSeekWanted = false; - } - - // *TODO: time-limit - but there isn't a lot we can do here, most - // time is spent in gstreamer's own opaque worker-threads. maybe - // we can do something sneaky like only unlock the video object - // for 'milliseconds' and otherwise hold the lock. - while (g_main_context_pending(g_main_loop_get_context(mPump))) - { - g_main_context_iteration(g_main_loop_get_context(mPump), FALSE); - } - - // check for availability of a new frame - - if (mVideoSink) - { - GST_OBJECT_LOCK(mVideoSink); - if (mVideoSink->retained_frame_ready) - { - DEBUGMSG("NEW FRAME READY"); - - if (mVideoSink->retained_frame_width != mCurrentWidth || - mVideoSink->retained_frame_height != mCurrentHeight) - // *TODO: also check for change in format - { - // just resize container, don't consume frame - int neww = mVideoSink->retained_frame_width; - int newh = mVideoSink->retained_frame_height; - - int newd = 4; - mTextureFormatPrimary = GL_RGBA; - mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; - - /* - int newd = SLVPixelFormatBytes[mVideoSink->retained_frame_format]; - if (SLV_PF_BGRX == mVideoSink->retained_frame_format) - { - mTextureFormatPrimary = GL_BGRA; - mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; - } - else - { - mTextureFormatPrimary = GL_RGBA; - mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; - } - */ - - GST_OBJECT_UNLOCK(mVideoSink); - - mCurrentRowbytes = neww * newd; - DEBUGMSG("video container resized to %dx%d", - neww, newh); - - mDepth = newd; - mCurrentWidth = neww; - mCurrentHeight = newh; - sizeChanged(); - return true; - } - - if (mPixels && - mCurrentHeight <= mHeight && - mCurrentWidth <= mWidth && - !mTextureSegmentName.empty()) - { - // we're gonna totally consume this frame - reset 'ready' flag - mVideoSink->retained_frame_ready = FALSE; - int destination_rowbytes = mWidth * mDepth; - for (int row=0; rowretained_frame_data - [mCurrentRowbytes * row], - mCurrentRowbytes); - } - - GST_OBJECT_UNLOCK(mVideoSink); - DEBUGMSG("NEW FRAME REALLY TRULY CONSUMED, TELLING HOST"); - - setDirty(0,0,mCurrentWidth,mCurrentHeight); - } - else - { - // new frame ready, but we're not ready to - // consume it. - - GST_OBJECT_UNLOCK(mVideoSink); - - DEBUGMSG("NEW FRAME not consumed, still waiting for a shm segment and/or shm resize"); - } - - return true; - } - else - { - // nothing to do yet. - GST_OBJECT_UNLOCK(mVideoSink); - return true; - } - } - - return true; -} - - -void -MediaPluginGStreamer010::mouseDown( int x, int y ) -{ - // do nothing -} - -void -MediaPluginGStreamer010::mouseUp( int x, int y ) -{ - // do nothing -} - -void -MediaPluginGStreamer010::mouseMove( int x, int y ) -{ - // do nothing -} - - -bool -MediaPluginGStreamer010::pause() -{ - DEBUGMSG("pausing media..."); - // todo: error-check this? - if (mDoneInit && mPlaybin) - { - llgst_element_set_state(mPlaybin, GST_STATE_PAUSED); - return true; - } - return false; -} - -bool -MediaPluginGStreamer010::stop() -{ - DEBUGMSG("stopping media..."); - // todo: error-check this? - if (mDoneInit && mPlaybin) - { - llgst_element_set_state(mPlaybin, GST_STATE_READY); - return true; - } - return false; -} - -bool -MediaPluginGStreamer010::play(double rate) -{ - // NOTE: we don't actually support non-natural rate. - - DEBUGMSG("playing media... rate=%f", rate); - // todo: error-check this? - if (mDoneInit && mPlaybin) - { - llgst_element_set_state(mPlaybin, GST_STATE_PLAYING); - return true; - } - return false; -} - -bool -MediaPluginGStreamer010::setVolume( float volume ) -{ - // we try to only update volume as conservatively as - // possible, as many gst-plugins-base versions up to at least - // November 2008 have critical race-conditions in setting volume - sigh - if (mVolume == volume) - return true; // nothing to do, everything's fine - - mVolume = volume; - if (mDoneInit && mPlaybin) - { - g_object_set(mPlaybin, "volume", mVolume, NULL); - return true; - } - - return false; -} - -bool -MediaPluginGStreamer010::seek(double time_sec) -{ - bool success = false; - if (mDoneInit && mPlaybin) - { - success = llgst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, - GstSeekFlags(GST_SEEK_FLAG_FLUSH | - GST_SEEK_FLAG_KEY_UNIT), - GST_SEEK_TYPE_SET, gint64(time_sec*GST_SECOND), - GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); - } - DEBUGMSG("MEDIA SEEK REQUEST to %fsec result was %d", - float(time_sec), int(success)); - return success; -} - -bool -MediaPluginGStreamer010::getTimePos(double &sec_out) -{ - bool got_position = false; - if (mDoneInit && mPlaybin) - { - gint64 pos; - GstFormat timefmt = GST_FORMAT_TIME; - got_position = - llgst_element_query_position && - llgst_element_query_position(mPlaybin, - &timefmt, - &pos); - got_position = got_position - && (timefmt == GST_FORMAT_TIME); - // GStreamer may have other ideas, but we consider the current position - // undefined if not PLAYING or PAUSED - got_position = got_position && - (GST_STATE(mPlaybin) == GST_STATE_PLAYING || - GST_STATE(mPlaybin) == GST_STATE_PAUSED); - if (got_position && !GST_CLOCK_TIME_IS_VALID(pos)) - { - if (GST_STATE(mPlaybin) == GST_STATE_PLAYING) - { - // if we're playing then we treat an invalid clock time - // as 0, for complicated reasons (insert reason here) - pos = 0; - } - else - { - got_position = false; - } - - } - // If all the preconditions succeeded... we can trust the result. - if (got_position) - { - sec_out = double(pos) / double(GST_SECOND); // gst to sec - } - } - return got_position; -} - -bool -MediaPluginGStreamer010::load() -{ - if (!mDoneInit) - return false; // error - - setStatus(STATUS_LOADING); - - DEBUGMSG("setting up media..."); - - mIsLooping = false; - mVolume = 0.1234567; // minor hack to force an initial volume update - - // Create a pumpable main-loop for this media - mPump = g_main_loop_new (NULL, FALSE); - if (!mPump) - { - setStatus(STATUS_ERROR); - return false; // error - } - - // instantiate a playbin element to do the hard work - mPlaybin = llgst_element_factory_make ("playbin", "play"); - if (!mPlaybin) - { - setStatus(STATUS_ERROR); - return false; // error - } - - // get playbin's bus - GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); - if (!bus) - { - setStatus(STATUS_ERROR); - return false; // error - } - mBusWatchID = llgst_bus_add_watch (bus, - llmediaimplgstreamer_bus_callback, - this); - llgst_object_unref (bus); - -#if 0 // not quite stable/correct yet - // get a visualizer element (bonus feature!) - char* vis_name = getenv("LL_GST_VIS_NAME"); - if (!vis_name || - (vis_name && std::string(vis_name)!="none")) - { - if (vis_name) - { - mVisualizer = llgst_element_factory_make (vis_name, "vis"); - } - if (!mVisualizer) - { - mVisualizer = llgst_element_factory_make ("libvisual_jess", "vis"); - if (!mVisualizer) - { - mVisualizer = llgst_element_factory_make ("goom", "vis"); - if (!mVisualizer) - { - mVisualizer = llgst_element_factory_make ("libvisual_lv_scope", "vis"); - if (!mVisualizer) - { - // That's okay, we don't NEED this. - } - } - } - } - } -#endif - - if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) { - // instantiate a custom video sink - mVideoSink = - GST_SLVIDEO(llgst_element_factory_make ("private-slvideo", "slvideo")); - if (!mVideoSink) - { - WARNMSG("Could not instantiate private-slvideo element."); - // todo: cleanup. - setStatus(STATUS_ERROR); - return false; // error - } - - // connect the pieces - g_object_set(mPlaybin, "video-sink", mVideoSink, NULL); - } - - if (mVisualizer) - { - g_object_set(mPlaybin, "vis-plugin", mVisualizer, NULL); - } - - return true; -} - -bool -MediaPluginGStreamer010::unload () -{ - if (!mDoneInit) - return false; // error - - DEBUGMSG("unloading media..."); - - // stop getting callbacks for this bus - g_source_remove(mBusWatchID); - mBusWatchID = 0; - - if (mPlaybin) - { - llgst_element_set_state (mPlaybin, GST_STATE_NULL); - llgst_object_unref (GST_OBJECT (mPlaybin)); - mPlaybin = NULL; - } - - if (mVisualizer) - { - llgst_object_unref (GST_OBJECT (mVisualizer)); - mVisualizer = NULL; - } - - if (mPump) - { - g_main_loop_quit(mPump); - mPump = NULL; - } - - mVideoSink = NULL; - - setStatus(STATUS_NONE); - - return true; -} - - -//static -bool -MediaPluginGStreamer010::startup() -{ - // first - check if GStreamer is explicitly disabled - if (NULL != getenv("LL_DISABLE_GSTREAMER")) - return false; - - // only do global GStreamer initialization once. - if (!mDoneInit) - { - g_thread_init(NULL); - - // Init the glib type system - we need it. - g_type_init(); - - // Get symbols! -#if LL_DARWIN - if (! grab_gst_syms("libgstreamer-0.10.dylib", - "libgstvideo-0.10.dylib") ) -#elseif LL_WINDOWS - if (! grab_gst_syms("libgstreamer-0.10.dll", - "libgstvideo-0.10.dll") ) -#else // linux or other ELFy unixoid - if (! grab_gst_syms("libgstreamer-0.10.so.0", - "libgstvideo-0.10.so.0") ) -#endif - { - WARNMSG("Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled."); - return false; - } - - if (llgst_segtrap_set_enabled) - { - llgst_segtrap_set_enabled(FALSE); - } - else - { - WARNMSG("gst_segtrap_set_enabled() is not available; plugin crashes won't be caught."); - } - -#if LL_LINUX - // Gstreamer tries a fork during init, waitpid-ing on it, - // which conflicts with any installed SIGCHLD handler... - struct sigaction tmpact, oldact; - if (llgst_registry_fork_set_enabled) { - // if we can disable SIGCHLD-using forking behaviour, - // do it. - llgst_registry_fork_set_enabled(false); - } - else { - // else temporarily install default SIGCHLD handler - // while GStreamer initialises - tmpact.sa_handler = SIG_DFL; - sigemptyset( &tmpact.sa_mask ); - tmpact.sa_flags = SA_SIGINFO; - sigaction(SIGCHLD, &tmpact, &oldact); - } -#endif // LL_LINUX - - // Protect against GStreamer resetting the locale, yuck. - static std::string saved_locale; - saved_locale = setlocale(LC_ALL, NULL); - - // finally, try to initialize GStreamer! - GError *err = NULL; - gboolean init_gst_success = llgst_init_check(NULL, NULL, &err); - - // restore old locale - setlocale(LC_ALL, saved_locale.c_str() ); - -#if LL_LINUX - // restore old SIGCHLD handler - if (!llgst_registry_fork_set_enabled) - sigaction(SIGCHLD, &oldact, NULL); -#endif // LL_LINUX - - if (!init_gst_success) // fail - { - if (err) - { - WARNMSG("GST init failed: %s", err->message); - g_error_free(err); - } - else - { - WARNMSG("GST init failed for unspecified reason."); - } - return false; - } - - // Init our custom plugins - only really need do this once. - gst_slvideo_init_class(); - - mDoneInit = true; - } - - return true; -} - - -void -MediaPluginGStreamer010::sizeChanged() -{ - // the shared writing space has possibly changed size/location/whatever - - // Check to see whether the movie's NATURAL size has been set yet - if (1 == mNaturalWidth && - 1 == mNaturalHeight) - { - mNaturalWidth = mCurrentWidth; - mNaturalHeight = mCurrentHeight; - DEBUGMSG("Media NATURAL size better detected as %dx%d", - mNaturalWidth, mNaturalHeight); - } - - // if the size has changed then the shm has changed and the app needs telling - if (mCurrentWidth != mPreviousWidth || - mCurrentHeight != mPreviousHeight) - { - mPreviousWidth = mCurrentWidth; - mPreviousHeight = mCurrentHeight; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); - message.setValue("name", mTextureSegmentName); - message.setValueS32("width", mNaturalWidth); - message.setValueS32("height", mNaturalHeight); - DEBUGMSG("<--- Sending size change request to application with name: '%s' - natural size is %d x %d", mTextureSegmentName.c_str(), mNaturalWidth, mNaturalHeight); - sendMessage(message); - } -} - - - -//static -bool -MediaPluginGStreamer010::closedown() -{ - if (!mDoneInit) - return false; // error - - ungrab_gst_syms(); - - mDoneInit = false; - - return true; -} - -MediaPluginGStreamer010::~MediaPluginGStreamer010() -{ - DEBUGMSG("MediaPluginGStreamer010 destructor"); - - closedown(); - - DEBUGMSG("GStreamer010 closing down"); -} - - -std::string -MediaPluginGStreamer010::getVersion() -{ - std::string plugin_version = "GStreamer010 media plugin, GStreamer version "; - if (mDoneInit && - llgst_version) - { - guint major, minor, micro, nano; - llgst_version(&major, &minor, µ, &nano); - plugin_version += llformat("%u.%u.%u.%u (runtime), %u.%u.%u.%u (headers)", (unsigned int)major, (unsigned int)minor, (unsigned int)micro, (unsigned int)nano, (unsigned int)GST_VERSION_MAJOR, (unsigned int)GST_VERSION_MINOR, (unsigned int)GST_VERSION_MICRO, (unsigned int)GST_VERSION_NANO); - } - else - { - plugin_version += "(unknown)"; - } - return plugin_version; -} - -void MediaPluginGStreamer010::receiveMessage(const char *message_string) -{ - //std::cerr << "MediaPluginGStreamer010::receiveMessage: received message: \"" << message_string << "\"" << std::endl; - - LLPluginMessage message_in; - - if(message_in.parse(message_string) >= 0) - { - std::string message_class = message_in.getClass(); - std::string message_name = message_in.getName(); - if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) - { - if(message_name == "init") - { - LLPluginMessage message("base", "init_response"); - LLSD versions = LLSD::emptyMap(); - versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; - message.setValueLLSD("versions", versions); - - if ( load() ) - { - DEBUGMSG("GStreamer010 media instance set up"); - } - else - { - WARNMSG("GStreamer010 media instance failed to set up"); - } - - message.setValue("plugin_version", getVersion()); - sendMessage(message); - } - else if(message_name == "idle") - { - // no response is necessary here. - double time = message_in.getValueReal("time"); - - // Convert time to milliseconds for update() - update((int)(time * 1000.0f)); - } - else if(message_name == "cleanup") - { - unload(); - closedown(); - } - else if(message_name == "shm_added") - { - SharedSegmentInfo info; - info.mAddress = message_in.getValuePointer("address"); - info.mSize = (size_t)message_in.getValueS32("size"); - std::string name = message_in.getValue("name"); - - std::ostringstream str; - INFOMSG("MediaPluginGStreamer010::receiveMessage: shared memory added, name: %s, size: %d, address: %p", name.c_str(), int(info.mSize), info.mAddress); - - mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); - } - else if(message_name == "shm_remove") - { - std::string name = message_in.getValue("name"); - - DEBUGMSG("MediaPluginGStreamer010::receiveMessage: shared memory remove, name = %s", name.c_str()); - - SharedSegmentMap::iterator iter = mSharedSegments.find(name); - if(iter != mSharedSegments.end()) - { - if(mPixels == iter->second.mAddress) - { - // This is the currently active pixel buffer. Make sure we stop drawing to it. - mPixels = NULL; - mTextureSegmentName.clear(); - - // Make sure the movie decoder is no longer pointed at the shared segment. - sizeChanged(); - } - mSharedSegments.erase(iter); - } - else - { - WARNMSG("MediaPluginGStreamer010::receiveMessage: unknown shared memory region!"); - } - - // Send the response so it can be cleaned up. - LLPluginMessage message("base", "shm_remove_response"); - message.setValue("name", name); - sendMessage(message); - } - else - { - std::ostringstream str; - INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown base message: %s", message_name.c_str()); - } - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) - { - if(message_name == "init") - { - // Plugin gets to decide the texture parameters to use. - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); - // lame to have to decide this now, it depends on the movie. Oh well. - mDepth = 4; - - mCurrentWidth = 1; - mCurrentHeight = 1; - mPreviousWidth = 1; - mPreviousHeight = 1; - mNaturalWidth = 1; - mNaturalHeight = 1; - mWidth = 1; - mHeight = 1; - mTextureWidth = 1; - mTextureHeight = 1; - - message.setValueU32("format", GL_RGBA); - message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV); - - message.setValueS32("depth", mDepth); - message.setValueS32("default_width", mWidth); - message.setValueS32("default_height", mHeight); - message.setValueU32("internalformat", GL_RGBA8); - message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. - message.setValueBoolean("allow_downsample", true); // we respond with grace and performance if asked to downscale - sendMessage(message); - } - else if(message_name == "size_change") - { - std::string name = message_in.getValue("name"); - S32 width = message_in.getValueS32("width"); - S32 height = message_in.getValueS32("height"); - S32 texture_width = message_in.getValueS32("texture_width"); - S32 texture_height = message_in.getValueS32("texture_height"); - - std::ostringstream str; - INFOMSG("---->Got size change instruction from application with shm name: %s - size is %d x %d", name.c_str(), width, height); - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); - message.setValue("name", name); - message.setValueS32("width", width); - message.setValueS32("height", height); - message.setValueS32("texture_width", texture_width); - message.setValueS32("texture_height", texture_height); - sendMessage(message); - - if(!name.empty()) - { - // Find the shared memory region with this name - SharedSegmentMap::iterator iter = mSharedSegments.find(name); - if(iter != mSharedSegments.end()) - { - INFOMSG("*** Got size change with matching shm, new size is %d x %d", width, height); - INFOMSG("*** Got size change with matching shm, texture size size is %d x %d", texture_width, texture_height); - - mPixels = (unsigned char*)iter->second.mAddress; - mTextureSegmentName = name; - mWidth = width; - mHeight = height; - - if (texture_width > 1 || - texture_height > 1) // not a dummy size from the app, a real explicit forced size - { - INFOMSG("**** = REAL RESIZE REQUEST FROM APP"); - - GST_OBJECT_LOCK(mVideoSink); - mVideoSink->resize_forced_always = true; - mVideoSink->resize_try_width = texture_width; - mVideoSink->resize_try_height = texture_height; - GST_OBJECT_UNLOCK(mVideoSink); - } - - mTextureWidth = texture_width; - mTextureHeight = texture_height; - } - } - } - else if(message_name == "load_uri") - { - std::string uri = message_in.getValue("uri"); - navigateTo( uri ); - sendStatus(); - } - else if(message_name == "mouse_event") - { - std::string event = message_in.getValue("event"); - S32 x = message_in.getValueS32("x"); - S32 y = message_in.getValueS32("y"); - - if(event == "down") - { - mouseDown(x, y); - } - else if(event == "up") - { - mouseUp(x, y); - } - else if(event == "move") - { - mouseMove(x, y); - }; - }; - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) - { - if(message_name == "stop") - { - stop(); - } - else if(message_name == "start") - { - double rate = 0.0; - if(message_in.hasValue("rate")) - { - rate = message_in.getValueReal("rate"); - } - // NOTE: we don't actually support rate. - play(rate); - } - else if(message_name == "pause") - { - pause(); - } - else if(message_name == "seek") - { - double time = message_in.getValueReal("time"); - // defer the actual seek in case we haven't - // really truly started yet in which case there - // is nothing to seek upon - mSeekWanted = true; - mSeekDestination = time; - } - else if(message_name == "set_loop") - { - bool loop = message_in.getValueBoolean("loop"); - mIsLooping = loop; - } - else if(message_name == "set_volume") - { - double volume = message_in.getValueReal("volume"); - setVolume(volume); - } - } - else - { - INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown message class: %s", message_class.c_str()); - } - } -} - -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) -{ - if (MediaPluginGStreamer010::startup()) - { - MediaPluginGStreamer010 *self = new MediaPluginGStreamer010(host_send_func, host_user_data); - *plugin_send_func = MediaPluginGStreamer010::staticReceiveMessage; - *plugin_user_data = (void*)self; - - return 0; // okay - } - else - { - return -1; // failed to init - } -} - -#else // LL_GSTREAMER010_ENABLED - -// Stubbed-out class with constructor/destructor (necessary or windows linker -// will just think its dead code and optimize it all out) -class MediaPluginGStreamer010 : public MediaPluginBase -{ -public: - MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); - ~MediaPluginGStreamer010(); - /* virtual */ void receiveMessage(const char *message_string); -}; - -MediaPluginGStreamer010::MediaPluginGStreamer010( - LLPluginInstance::sendMessageFunction host_send_func, - void *host_user_data ) : - MediaPluginBase(host_send_func, host_user_data) -{ - // no-op -} - -MediaPluginGStreamer010::~MediaPluginGStreamer010() -{ - // no-op -} - -void MediaPluginGStreamer010::receiveMessage(const char *message_string) -{ - // no-op -} - -// We're building without GStreamer enabled. Just refuse to initialize. -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) -{ - return -1; -} - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer10/CMakeLists.txt b/indra/media_plugins/gstreamer10/CMakeLists.txt new file mode 100644 index 00000000000..279e07b2260 --- /dev/null +++ b/indra/media_plugins/gstreamer10/CMakeLists.txt @@ -0,0 +1,40 @@ +# -*- cmake -*- + +project(media_plugin_gstreamer10) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLMath) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(OpenGL) +include(GLIB) + +include(GStreamer10Plugin) + +### media_plugin_gstreamer10 + +set(media_plugin_gstreamer10_SOURCE_FILES + media_plugin_gstreamer10.cpp + ) + +set(media_plugin_gstreamer10_HEADER_FILES + llmediaimplgstreamer_syms.h + ) + +add_library(media_plugin_gstreamer10 + SHARED + ${media_plugin_gstreamer10_SOURCE_FILES} +) + +target_link_libraries(media_plugin_gstreamer10 media_plugin_base ll::gstreamer10 ) + +if (WINDOWS) + set_target_properties( + media_plugin_gstreamer10 + PROPERTIES + LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMT" + ) +endif (WINDOWS) diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc new file mode 100644 index 00000000000..6f5bb04bdfe --- /dev/null +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc @@ -0,0 +1,71 @@ +#define G gstSymbolGrabber + +LL_GRAB_SYM(G, true, gst_buffer_new, GstBuffer*, void) +LL_GRAB_SYM(G, true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*) +LL_GRAB_SYM(G, true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err) +LL_GRAB_SYM(G, true, gst_message_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_message_type_get_name, const gchar*, GstMessageType type) +LL_GRAB_SYM(G, true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(G, true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(G, true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending) +LL_GRAB_SYM(G, true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state) +LL_GRAB_SYM(G, true, gst_object_unref, void, gpointer object) +LL_GRAB_SYM(G, true, gst_object_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_pipeline_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline) +LL_GRAB_SYM(G, true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data) +LL_GRAB_SYM(G, true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name) +LL_GRAB_SYM(G, true, gst_element_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template) +LL_GRAB_SYM(G, true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp) +LL_GRAB_SYM(G, true, gst_caps_from_string, GstCaps *, const gchar *string) +LL_GRAB_SYM(G, true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index) +LL_GRAB_SYM(G, true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type) +LL_GRAB_SYM(G, true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value) +LL_GRAB_SYM(G, true, gst_structure_get_value, const GValue *, const GstStructure *structure, const gchar *fieldname) +LL_GRAB_SYM(G, true, gst_value_get_fraction_numerator, gint, const GValue *value) +LL_GRAB_SYM(G, true, gst_value_get_fraction_denominator, gint, const GValue *value) +LL_GRAB_SYM(G, true, gst_structure_get_name, const gchar *, const GstStructure *structure) +LL_GRAB_SYM(G, true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64) + +LL_GRAB_SYM(G, false, gst_registry_fork_set_enabled, void, gboolean enabled) +LL_GRAB_SYM(G, false, gst_segtrap_set_enabled, void, gboolean enabled) +LL_GRAB_SYM(G, false, gst_message_parse_buffering, void, GstMessage *message, gint *percent) +LL_GRAB_SYM(G, false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(G, false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur) +LL_GRAB_SYM(G, false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano) + +LL_GRAB_SYM(G, true, gst_message_parse_tag, void, GstMessage *, GstTagList **) +LL_GRAB_SYM(G, true, gst_tag_list_foreach, void, const GstTagList *, GstTagForeachFunc, gpointer) +LL_GRAB_SYM(G, true, gst_tag_list_get_tag_size, guint, const GstTagList *, const gchar *) +LL_GRAB_SYM(G, true, gst_tag_list_get_value_index, const GValue *, const GstTagList *, const gchar *, guint) + +LL_GRAB_SYM(G, true, gst_caps_new_simple, GstCaps*, const char *, const char*, ... ) + +LL_GRAB_SYM(G, true, gst_sample_get_caps, GstCaps*, GstSample* ) +LL_GRAB_SYM(G, true, gst_sample_get_buffer, GstBuffer*, GstSample* ) +LL_GRAB_SYM(G, true, gst_buffer_map, gboolean, GstBuffer*, GstMapInfo*, GstMapFlags ) +LL_GRAB_SYM(G, true, gst_buffer_unmap, void, GstBuffer*, GstMapInfo* ) + +LL_GRAB_SYM(G, true, gst_app_sink_set_caps, void, GstAppSink*, GstCaps const* ) +LL_GRAB_SYM(G, true, gst_app_sink_pull_sample, GstSample*, GstAppSink* ) + +LL_GRAB_SYM(G, true, g_free, void, gpointer ) +LL_GRAB_SYM(G, true, g_error_free, void, GError* ) + +LL_GRAB_SYM(G, true, g_main_context_pending, gboolean, GMainContext* ) +LL_GRAB_SYM(G, true, g_main_loop_get_context, GMainContext*, GMainLoop* ) +LL_GRAB_SYM(G, true, g_main_context_iteration, gboolean, GMainContext*, gboolean ) +LL_GRAB_SYM(G, true, g_main_loop_new, GMainLoop*, GMainContext*, gboolean ) +LL_GRAB_SYM(G, true, g_main_loop_quit, void, GMainLoop* ) +LL_GRAB_SYM(G, true, gst_mini_object_unref, void, GstMiniObject* ) +LL_GRAB_SYM(G, true, g_object_set, void, gpointer, gchar const*, ... ) +LL_GRAB_SYM(G, true, g_source_remove, gboolean, guint ) +LL_GRAB_SYM(G, true, g_value_get_string, gchar const*, GValue const* ) + +LL_GRAB_SYM(G, true, gst_debug_set_active, void, gboolean ) +LL_GRAB_SYM(G, true, gst_debug_add_log_function, void, GstLogFunction, gpointer, GDestroyNotify ) +LL_GRAB_SYM(G, true, gst_debug_set_default_threshold, void, GstDebugLevel ) +LL_GRAB_SYM(G, true, gst_debug_message_get , gchar const*, GstDebugMessage * ) + +#undef G diff --git a/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp b/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp new file mode 100644 index 00000000000..0f45c151a20 --- /dev/null +++ b/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp @@ -0,0 +1,958 @@ +/** + * @file media_plugin_gstreamer10.cpp + * @brief GStreamer-1.0 plugin for LLMedia API plugin system + * + * @cond + * $LicenseInfo:firstyear=2016&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2016, Linden Research, Inc. / Nicky Dasmijn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * @endcond + */ + +#define FLIP_Y + +#include "linden_common.h" + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#define G_DISABLE_CAST_CHECKS +extern "C" { +#include +#include +} + +SymbolGrabber gstSymbolGrabber; + +#include "llmediaimplgstreamer_syms_raw.inc" + +static inline void llgst_caps_unref( GstCaps * caps ) +{ + llgst_mini_object_unref( GST_MINI_OBJECT_CAST( caps ) ); +} + +static inline void llgst_sample_unref( GstSample *aSample ) +{ + llgst_mini_object_unref( GST_MINI_OBJECT_CAST( aSample ) ); +} + +////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginGStreamer10 : public MediaPluginBase +{ +public: + MediaPluginGStreamer10(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginGStreamer10(); + + /* virtual */ void receiveMessage(const char *message_string); + + static bool startup(); + static bool closedown(); + + gboolean processGSTEvents(GstBus *bus, GstMessage *message); + +private: + std::string getVersion(); + bool navigateTo( const std::string urlIn ); + bool seek( double time_sec ); + bool setVolume( float volume ); + + // misc + bool pause(); + bool stop(); + bool play(double rate); + bool getTimePos(double &sec_out); + + double MIN_LOOP_SEC = 1.0F; + U32 INTERNAL_TEXTURE_SIZE = 1024; + + bool mIsLooping; + + enum ECommand { + COMMAND_NONE, + COMMAND_STOP, + COMMAND_PLAY, + COMMAND_FAST_FORWARD, + COMMAND_FAST_REWIND, + COMMAND_PAUSE, + COMMAND_SEEK, + }; + ECommand mCommand; + +private: + bool unload(); + bool load(); + + bool update(int milliseconds); + void mouseDown( int x, int y ); + void mouseUp( int x, int y ); + void mouseMove( int x, int y ); + + static bool mDoneInit; + + guint mBusWatchID; + + float mVolume; + + int mDepth; + + // padded texture size we need to write into + int mTextureWidth; + int mTextureHeight; + + bool mSeekWanted; + double mSeekDestination; + + // Very GStreamer-specific + GMainLoop *mPump; // event pump for this media + GstElement *mPlaybin; + GstAppSink *mAppSink; +}; + +//static +bool MediaPluginGStreamer10::mDoneInit = false; + +MediaPluginGStreamer10::MediaPluginGStreamer10( LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) + : MediaPluginBase(host_send_func, host_user_data) + , mBusWatchID ( 0 ) + , mSeekWanted(false) + , mSeekDestination(0.0) + , mPump ( nullptr ) + , mPlaybin ( nullptr ) + , mAppSink ( nullptr ) + , mCommand ( COMMAND_NONE ) +{ +} + +gboolean MediaPluginGStreamer10::processGSTEvents(GstBus *bus, GstMessage *message) +{ + if (!message) + return TRUE; // shield against GStreamer bug + + switch (GST_MESSAGE_TYPE (message)) + { + case GST_MESSAGE_BUFFERING: + { + // NEEDS GST 0.10.11+ + if (llgst_message_parse_buffering) + { + gint percent = 0; + llgst_message_parse_buffering(message, &percent); + } + break; + } + case GST_MESSAGE_STATE_CHANGED: + { + GstState old_state; + GstState new_state; + GstState pending_state; + llgst_message_parse_state_changed(message, + &old_state, + &new_state, + &pending_state); + + switch (new_state) + { + case GST_STATE_VOID_PENDING: + break; + case GST_STATE_NULL: + break; + case GST_STATE_READY: + setStatus(STATUS_LOADED); + break; + case GST_STATE_PAUSED: + setStatus(STATUS_PAUSED); + break; + case GST_STATE_PLAYING: + setStatus(STATUS_PLAYING); + break; + } + break; + } + case GST_MESSAGE_ERROR: + { + GError *err = nullptr; + gchar *debug = nullptr; + + llgst_message_parse_error (message, &err, &debug); + if (err) + llg_error_free (err); + llg_free (debug); + + mCommand = COMMAND_STOP; + + setStatus(STATUS_ERROR); + + break; + } + case GST_MESSAGE_INFO: + { + if (llgst_message_parse_info) + { + GError *err = nullptr; + gchar *debug = nullptr; + + llgst_message_parse_info (message, &err, &debug); + if (err) + llg_error_free (err); + llg_free (debug); + } + break; + } + case GST_MESSAGE_WARNING: + { + GError *err = nullptr; + gchar *debug = nullptr; + + llgst_message_parse_warning (message, &err, &debug); + if (err) + llg_error_free (err); + llg_free (debug); + + break; + } + case GST_MESSAGE_EOS: + /* end-of-stream */ + if (mIsLooping) + { + double eos_pos_sec = 0.0F; + bool got_eos_position = getTimePos(eos_pos_sec); + + if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC) + { + // if we know that the movie is really short, don't + // loop it else it can easily become a time-hog + // because of GStreamer spin-up overhead + // inject a COMMAND_PAUSE + mCommand = COMMAND_PAUSE; + } + else + { + stop(); + play(1.0); + } + } + else // not a looping media + { + // inject a COMMAND_STOP + mCommand = COMMAND_STOP; + } + break; + default: + /* unhandled message */ + break; + } + + /* we want to be notified again the next time there is a message + * on the bus, so return true (false means we want to stop watching + * for messages on the bus and our callback should not be called again) + */ + return TRUE; +} + +extern "C" { + gboolean llmediaimplgstreamer_bus_callback (GstBus *bus, + GstMessage *message, + gpointer data) + { + MediaPluginGStreamer10 *impl = (MediaPluginGStreamer10*)data; + return impl->processGSTEvents(bus, message); + } +} // extern "C" + + + +bool MediaPluginGStreamer10::navigateTo ( const std::string urlIn ) +{ + if (!mDoneInit) + return false; // error + + setStatus(STATUS_LOADING); + + mSeekWanted = false; + + if (nullptr == mPump || nullptr == mPlaybin) + { + setStatus(STATUS_ERROR); + return false; // error + } + + llg_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), nullptr); + + // navigateTo implicitly plays, too. + play(1.0); + + return true; +} + + +class GstSampleUnref +{ + GstSample *mT; +public: + GstSampleUnref( GstSample *aT ) + : mT( aT ) + { llassert_always( mT ); } + + ~GstSampleUnref( ) + { llgst_sample_unref( mT ); } +}; + +bool MediaPluginGStreamer10::update(int milliseconds) +{ + if (!mDoneInit) + return false; // error + + // DEBUGMSG("updating media..."); + + // sanity check + if (nullptr == mPump || nullptr == mPlaybin) + { + return false; + } + + // see if there's an outstanding seek wanted + if (mSeekWanted && + // bleh, GST has to be happy that the movie is really truly playing + // or it may quietly ignore the seek (with rtsp:// at least). + (GST_STATE(mPlaybin) == GST_STATE_PLAYING)) + { + seek(mSeekDestination); + mSeekWanted = false; + } + + // *TODO: time-limit - but there isn't a lot we can do here, most + // time is spent in gstreamer's own opaque worker-threads. maybe + // we can do something sneaky like only unlock the video object + // for 'milliseconds' and otherwise hold the lock. + while (llg_main_context_pending(llg_main_loop_get_context(mPump))) + { + llg_main_context_iteration(llg_main_loop_get_context(mPump), FALSE); + } + + // check for availability of a new frame + + if( !mAppSink ) + return true; + + if( GST_STATE(mPlaybin) != GST_STATE_PLAYING) // Do not try to pull a sample if not in playing state + return true; + + GstSample *pSample = llgst_app_sink_pull_sample( mAppSink ); + if(!pSample) + return false; // Done playing + + GstSampleUnref oSampleUnref( pSample ); + GstCaps *pCaps = llgst_sample_get_caps ( pSample ); + if (!pCaps) + return false; + + gint width = 0, height = 0; + GstStructure *pStruct = llgst_caps_get_structure ( pCaps, 0); + + if(!llgst_structure_get_int ( pStruct, "width", &width) ) + width = 0; + if(!llgst_structure_get_int ( pStruct, "height", &height) ) + height = 0; + + if( !mPixels || width == 0 || height == 0) + return true; + + GstBuffer *pBuffer = llgst_sample_get_buffer ( pSample ); + GstMapInfo map; + llgst_buffer_map ( pBuffer, &map, GST_MAP_READ); + + // Our render buffer is always 1kx1k + + U32 rowSkip = INTERNAL_TEXTURE_SIZE / mTextureHeight; + U32 colSkip = INTERNAL_TEXTURE_SIZE / mTextureWidth; + + for (int row = 0; row < mTextureHeight; ++row) + { + U8 const *pTexelIn = map.data + (row*rowSkip * width *3); +#ifndef FLIP_Y + U8 *pTexelOut = mPixels + (row * mTextureWidth * mDepth ); +#else + U8 *pTexelOut = mPixels + ((mTextureHeight-row-1) * mTextureWidth * mDepth ); +#endif + for( int col = 0; col < mTextureWidth; ++col ) + { + pTexelOut[ 0 ] = pTexelIn[0]; + pTexelOut[ 1 ] = pTexelIn[1]; + pTexelOut[ 2 ] = pTexelIn[2]; + pTexelOut += mDepth; + pTexelIn += colSkip*3; + } + } + + llgst_buffer_unmap( pBuffer, &map ); + setDirty(0,0,mTextureWidth,mTextureHeight); + + return true; +} + +void MediaPluginGStreamer10::mouseDown( int x, int y ) +{ + // do nothing +} + +void MediaPluginGStreamer10::mouseUp( int x, int y ) +{ + // do nothing +} + +void MediaPluginGStreamer10::mouseMove( int x, int y ) +{ + // do nothing +} + + +bool MediaPluginGStreamer10::pause() +{ + // todo: error-check this? + if (mDoneInit && mPlaybin) + { + llgst_element_set_state(mPlaybin, GST_STATE_PAUSED); + return true; + } + return false; +} + +bool MediaPluginGStreamer10::stop() +{ + // todo: error-check this? + if (mDoneInit && mPlaybin) + { + llgst_element_set_state(mPlaybin, GST_STATE_READY); + return true; + } + return false; +} + +bool MediaPluginGStreamer10::play(double rate) +{ + // NOTE: we don't actually support non-natural rate. + + // todo: error-check this? + if (mDoneInit && mPlaybin) + { + llgst_element_set_state(mPlaybin, GST_STATE_PLAYING); + return true; + } + return false; +} + +bool MediaPluginGStreamer10::setVolume( float volume ) +{ + // we try to only update volume as conservatively as + // possible, as many gst-plugins-base versions up to at least + // November 2008 have critical race-conditions in setting volume - sigh + if (mVolume == volume) + return true; // nothing to do, everything's fine + + mVolume = volume; + if (mDoneInit && mPlaybin) + { + llg_object_set(mPlaybin, "volume", mVolume, nullptr); + return true; + } + + return false; +} + +bool MediaPluginGStreamer10::seek(double time_sec) +{ + bool success = false; + if (mDoneInit && mPlaybin) + { + success = llgst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, + GstSeekFlags(GST_SEEK_FLAG_FLUSH | + GST_SEEK_FLAG_KEY_UNIT), + GST_SEEK_TYPE_SET, gint64(time_sec*GST_SECOND), + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + } + return success; +} + +bool MediaPluginGStreamer10::getTimePos(double &sec_out) +{ + bool got_position = false; + if (mDoneInit && mPlaybin) + { + gint64 pos(0); + GstFormat timefmt = GST_FORMAT_TIME; + got_position = + llgst_element_query_position && + llgst_element_query_position(mPlaybin, + &timefmt, + &pos); + got_position = got_position + && (timefmt == GST_FORMAT_TIME); + // GStreamer may have other ideas, but we consider the current position + // undefined if not PLAYING or PAUSED + got_position = got_position && + (GST_STATE(mPlaybin) == GST_STATE_PLAYING || + GST_STATE(mPlaybin) == GST_STATE_PAUSED); + if (got_position && !GST_CLOCK_TIME_IS_VALID(pos)) + { + if (GST_STATE(mPlaybin) == GST_STATE_PLAYING) + { + // if we're playing then we treat an invalid clock time + // as 0, for complicated reasons (insert reason here) + pos = 0; + } + else + { + got_position = false; + } + + } + // If all the preconditions succeeded... we can trust the result. + if (got_position) + { + sec_out = double(pos) / double(GST_SECOND); // gst to sec + } + } + return got_position; +} + +bool MediaPluginGStreamer10::load() +{ + if (!mDoneInit) + return false; // error + + setStatus(STATUS_LOADING); + + mIsLooping = false; + mVolume = 0.1234567f; // minor hack to force an initial volume update + + // Create a pumpable main-loop for this media + mPump = llg_main_loop_new (nullptr, FALSE); + if (!mPump) + { + setStatus(STATUS_ERROR); + return false; // error + } + + // instantiate a playbin element to do the hard work + mPlaybin = llgst_element_factory_make ("playbin", ""); + if (!mPlaybin) + { + setStatus(STATUS_ERROR); + return false; // error + } + + // get playbin's bus + GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); + if (!bus) + { + setStatus(STATUS_ERROR); + return false; // error + } + mBusWatchID = llgst_bus_add_watch (bus, + llmediaimplgstreamer_bus_callback, + this); + llgst_object_unref (bus); + + mAppSink = (GstAppSink*)(llgst_element_factory_make ("appsink", "")); + + GstCaps* pCaps = llgst_caps_new_simple( "video/x-raw", + "format", G_TYPE_STRING, "RGB", + "width", G_TYPE_INT, INTERNAL_TEXTURE_SIZE, + "height", G_TYPE_INT, INTERNAL_TEXTURE_SIZE, + nullptr ); + + llgst_app_sink_set_caps( mAppSink, pCaps ); + llgst_caps_unref( pCaps ); + + if (!mAppSink) + { + setStatus(STATUS_ERROR); + return false; + } + + llg_object_set(mPlaybin, "video-sink", mAppSink, nullptr); + + return true; +} + +bool MediaPluginGStreamer10::unload () +{ + if (!mDoneInit) + return false; // error + + // stop getting callbacks for this bus + llg_source_remove(mBusWatchID); + mBusWatchID = 0; + + if (mPlaybin) + { + llgst_element_set_state (mPlaybin, GST_STATE_NULL); + llgst_object_unref (GST_OBJECT (mPlaybin)); + mPlaybin = nullptr; + } + + if (mPump) + { + llg_main_loop_quit(mPump); + mPump = nullptr; + } + + mAppSink = nullptr; + + setStatus(STATUS_NONE); + + return true; +} + +void LogFunction(GstDebugCategory *category, GstDebugLevel level, const gchar *file, const gchar *function, gint line, GObject *object, GstDebugMessage *message, gpointer user_data ) +{ + std::cerr << file << ":" << line << "(" << function << "): " << llgst_debug_message_get( message ) << std::endl; +} + +//static +bool MediaPluginGStreamer10::startup() +{ + // first - check if GStreamer is explicitly disabled + if (nullptr != getenv("LL_DISABLE_GSTREAMER")) + return false; + + // only do global GStreamer initialization once. + if (!mDoneInit) + { + ll_init_apr(); + + // Get symbols! + std::vector< std::string > vctDSONames; + vctDSONames.push_back( "libgstreamer-1.0.so.0" ); + vctDSONames.push_back( "libgstapp-1.0.so.0" ); + vctDSONames.push_back( "libglib-2.0.so.0" ); + vctDSONames.push_back( "libgobject-2.0.so" ); + if( !gstSymbolGrabber.grabSymbols( vctDSONames ) ) + return false; + + if (llgst_segtrap_set_enabled) + { + llgst_segtrap_set_enabled(FALSE); + } + + // Gstreamer tries a fork during init, waitpid-ing on it, + // which conflicts with any installed SIGCHLD handler... + struct sigaction tmpact, oldact; + if (llgst_registry_fork_set_enabled ) { + // if we can disable SIGCHLD-using forking behaviour, + // do it. + llgst_registry_fork_set_enabled(false); + } + else { + // else temporarily install default SIGCHLD handler + // while GStreamer initialises + tmpact.sa_handler = SIG_DFL; + sigemptyset( &tmpact.sa_mask ); + tmpact.sa_flags = SA_SIGINFO; + sigaction(SIGCHLD, &tmpact, &oldact); + } + // Protect against GStreamer resetting the locale, yuck. + static std::string saved_locale; + saved_locale = setlocale(LC_ALL, nullptr); + + llgst_debug_set_default_threshold( GST_LEVEL_WARNING ); + llgst_debug_add_log_function( LogFunction, nullptr, nullptr ); + llgst_debug_set_active( false ); + + // finally, try to initialize GStreamer! + GError *err = nullptr; + gboolean init_gst_success = llgst_init_check(nullptr, nullptr, &err); + + // restore old locale + setlocale(LC_ALL, saved_locale.c_str() ); + + // restore old SIGCHLD handler + if (!llgst_registry_fork_set_enabled) + sigaction(SIGCHLD, &oldact, nullptr); + + if (!init_gst_success) // fail + { + if (err) + llg_error_free(err); + return false; + } + + mDoneInit = true; + } + + return true; +} + +//static +bool MediaPluginGStreamer10::closedown() +{ + if (!mDoneInit) + return false; // error + + gstSymbolGrabber.ungrabSymbols(); + mDoneInit = false; + + return true; +} + +MediaPluginGStreamer10::~MediaPluginGStreamer10() +{ + closedown(); +} + +std::string MediaPluginGStreamer10::getVersion() +{ + std::string plugin_version = "GStreamer10 media plugin, GStreamer version "; + if (mDoneInit && + llgst_version) + { + guint major, minor, micro, nano; + llgst_version(&major, &minor, µ, &nano); + plugin_version += llformat("%u.%u.%u.%u (runtime), %u.%u.%u.%u (headers)", (unsigned int)major, (unsigned int)minor, + (unsigned int)micro, (unsigned int)nano, (unsigned int)GST_VERSION_MAJOR, (unsigned int)GST_VERSION_MINOR, + (unsigned int)GST_VERSION_MICRO, (unsigned int)GST_VERSION_NANO); + } + else + { + plugin_version += "(unknown)"; + } + return plugin_version; +} + +void MediaPluginGStreamer10::receiveMessage(const char *message_string) +{ + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; + message.setValueLLSD("versions", versions); + + load(); + + message.setValue("plugin_version", getVersion()); + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + double time = message_in.getValueReal("time"); + + // Convert time to milliseconds for update() + update((int)(time * 1000.0f)); + } + else if(message_name == "cleanup") + { + unload(); + closedown(); + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = nullptr; + mTextureSegmentName.clear(); + } + mSharedSegments.erase(iter); + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "init") + { + // Plugin gets to decide the texture parameters to use. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + // lame to have to decide this now, it depends on the movie. Oh well. + mDepth = 4; + + mTextureWidth = 1; + mTextureHeight = 1; + + message.setValueU32("format", GL_RGBA); + message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV); + + message.setValueS32("depth", mDepth); + message.setValueS32("default_width", INTERNAL_TEXTURE_SIZE ); + message.setValueS32("default_height", INTERNAL_TEXTURE_SIZE ); + message.setValueU32("internalformat", GL_RGBA8); + message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. + message.setValueBoolean("allow_downsample", true); // we respond with grace and performance if asked to downscale + sendMessage(message); + } + else if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + mPixels = (unsigned char*)iter->second.mAddress; + mTextureSegmentName = name; + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + memset( mPixels, 0, mTextureWidth*mTextureHeight*mDepth ); + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); + message.setValue("name", mTextureSegmentName); + message.setValueS32("width", INTERNAL_TEXTURE_SIZE ); + message.setValueS32("height", INTERNAL_TEXTURE_SIZE ); + sendMessage(message); + + } + } + else if(message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + navigateTo( uri ); + sendStatus(); + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + + if(event == "down") + { + mouseDown(x, y); + } + else if(event == "up") + { + mouseUp(x, y); + } + else if(event == "move") + { + mouseMove(x, y); + }; + }; + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if(message_name == "stop") + { + stop(); + } + else if(message_name == "start") + { + double rate = 0.0; + if(message_in.hasValue("rate")) + { + rate = message_in.getValueReal("rate"); + } + // NOTE: we don't actually support rate. + play(rate); + } + else if(message_name == "pause") + { + pause(); + } + else if(message_name == "seek") + { + double time = message_in.getValueReal("time"); + // defer the actual seek in case we haven't + // really truly started yet in which case there + // is nothing to seek upon + mSeekWanted = true; + mSeekDestination = time; + } + else if(message_name == "set_loop") + { + bool loop = message_in.getValueBoolean("loop"); + mIsLooping = loop; + } + else if(message_name == "set_volume") + { + double volume = message_in.getValueReal("volume"); + setVolume(volume); + } + } + } +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + if( MediaPluginGStreamer10::startup() ) + { + MediaPluginGStreamer10 *self = new MediaPluginGStreamer10(host_send_func, host_user_data); + *plugin_send_func = MediaPluginGStreamer10::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; // okay + } + else + { + return -1; // failed to init + } +} diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 0f7670a57aa..b49bb41b001 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -13,7 +13,6 @@ include(BuildPackagesInfo) include(BuildVersion) include(CMakeCopyIfDifferent) include(CubemapToEquirectangularJS) -include(DBusGlib) include(DragDrop) if (USE_DISCORD) include(Discord) @@ -274,7 +273,6 @@ set(viewer_SOURCE_FILES llfloaterpay.cpp llfloaterperformance.cpp llfloaterperms.cpp - llfloaterpostprocess.cpp llfloaterprofile.cpp llfloaterpreference.cpp llfloaterpreferencesgraphicsadvanced.cpp @@ -953,7 +951,6 @@ set(viewer_HEADER_FILES llfloaterpay.h llfloaterperformance.h llfloaterperms.h - llfloaterpostprocess.h llfloaterprofile.h llfloaterpreference.h llfloaterpreferencesgraphicsadvanced.h @@ -1486,7 +1483,6 @@ if (LINUX) PROPERTIES COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" ) - LIST(APPEND viewer_SOURCE_FILES llappviewerlinux_api_dbus.cpp) SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") endif (LINUX) @@ -1675,6 +1671,7 @@ set(viewer_APPSETTINGS_FILES packages-info.txt featuretable.txt featuretable_mac.txt + featuretable_linux.txt ) source_group("App Settings" FILES ${viewer_APPSETTINGS_FILES}) @@ -1698,6 +1695,15 @@ set_source_files_properties(${viewer_CHARACTER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) list(APPEND viewer_SOURCE_FILES ${viewer_CHARACTER_FILES}) +set(viewer_MISC_FILES + viewer_manifest.py + ) + +set_source_files_properties(${viewer_MISC_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND viewer_SOURCE_FILES ${viewer_MISC_FILES}) + if (WINDOWS) file(GLOB viewer_INSTALLER_FILES installers/windows/*.nsi) @@ -2061,8 +2067,11 @@ if (LINUX) set(COPY_INPUT_DEPENDENCIES ${VIEWER_BINARY_NAME} SLPlugin - #media_plugin_gstreamer010 - llcommon + media_plugin_cef + media_plugin_gstreamer10 + media_plugin_libvlc + media_plugin_example + llwebrtc ) #if (NOT USE_BUGSPLAT) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index d6a1fbd124f..c7c3e60660a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5053,6 +5053,28 @@ Value 0 + MediaPluginPipeWireVolumeCatcher + + Comment + Use PipeWire instead of PulseAudio for controlling web media volume. + Persist + 1 + Type + Boolean + Value + 0 + + MediaPluginForceVLC + + Comment + Force use of VLC based media plugin. (Linux Only) + Persist + 1 + Type + Boolean + Value + 0 + MediaControlFadeTime Comment diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt index d8d4f084291..c53e8280205 100644 --- a/indra/newview/featuretable_linux.txt +++ b/indra/newview/featuretable_linux.txt @@ -1,10 +1,10 @@ -version 30 +version 33 // The version number above should be incremented IF AND ONLY IF some // change has been made that is sufficiently important to justify // resetting the graphics preferences of all users to the recommended // defaults. This should be as rare an event as we can manage. -// NOTE: This is mostly identical to featuretable_mac.txt with a few differences +// NOTE: This is mostly identical to featuretable_mac.txt with a few differences // Should be combined into one table // @@ -28,27 +28,27 @@ version 30 // list all RenderAnisotropic 1 1 -RenderAvatarCloth 1 1 RenderAvatarLODFactor 1 1.0 RenderAvatarPhysicsLODFactor 1 1.0 RenderAvatarMaxNonImpostors 1 16 RenderAvatarMaxComplexity 1 350000 RenderAutoMuteSurfaceAreaLimit 1 1000.0 RenderCubeMap 1 1 -RenderDelayVBUpdate 1 0 RenderFarClip 1 256 RenderFlexTimeFactor 1 1.0 RenderFogRatio 1 4.0 RenderGamma 1 0 RenderGlowResolutionPow 1 9 -RenderGround 1 1 RenderMaxPartCount 1 8192 RenderObjectBump 1 1 -RenderLocalLights 1 1 -RenderReflectionDetail 1 4 +RenderLocalLightCount 1 4096 +RenderTransparentWater 1 1 +RenderReflectionsEnabled 1 1 +RenderReflectionProbeDetail 1 2 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 -RenderTransparentWater 1 1 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTreeLODFactor 1 1.0 RenderVBOEnable 1 1 RenderVBOMappingDisable 1 1 @@ -61,58 +61,38 @@ Disregard128DefaultDrawDistance 1 1 Disregard96DefaultDrawDistance 1 1 RenderCompressTextures 1 1 RenderShaderLightingMaxLevel 1 3 +RenderReflectionProbeLevel 1 3 RenderDeferred 1 1 RenderDeferredSSAO 1 1 -RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 -RenderFSAASamples 1 16 +RenderUseStreamVBO 1 1 +RenderFSAAType 1 2 +RenderFSAASamples 1 3 RenderMaxTextureIndex 1 16 +RenderGLContextCoreProfile 1 1 +RenderGLMultiThreadedTextures 1 0 +RenderGLMultiThreadedMedia 1 0 +RenderReflectionProbeResolution 1 128 +RenderScreenSpaceReflections 1 1 RenderMirrors 1 1 - -// -// Low Graphics Settings (fixed function) -// -list LowFixedFunction -RenderAnisotropic 1 0 -RenderAvatarCloth 1 0 -RenderAvatarLODFactor 1 0 -RenderAvatarPhysicsLODFactor 1 0 -RenderAvatarMaxNonImpostors 1 3 -RenderAvatarMaxComplexity 1 25000 -RenderFarClip 1 64 -RenderFlexTimeFactor 1 0 -RenderGlowResolutionPow 1 8 -RenderLocalLights 1 0 -RenderMaxPartCount 1 0 -RenderObjectBump 1 0 -RenderReflectionDetail 1 0 -RenderTerrainDetail 1 0 -RenderTerrainLODFactor 1 1 -RenderTransparentWater 1 0 -RenderTreeLODFactor 1 0 -RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 0 -RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderUseAdvancedAtmospherics 1 0 -RenderShadowDetail 1 0 -WLSkyDetail 1 48 -RenderFSAASamples 1 0 -RenderMirrors 1 0 -RenderHeroProbeResolution 1 256 -RenderHeroProbeDistance 1 4 -RenderHeroProbeUpdateRate 1 6 +RenderHeroProbeResolution 1 2048 +RenderHeroProbeDistance 1 16 +RenderHeroProbeUpdateRate 1 6 RenderHeroProbeConservativeUpdateMultiplier 1 16 +RenderDownScaleMethod 1 0 +RenderCASSharpness 1 1 RenderExposure 1 4 RenderTonemapType 1 1 RenderTonemapMix 1 1 +RenderDisableVintageMode 1 1 +RenderMaxTextureResolution 1 2048 +RenderReflectionProbeCount 1 256 // // Low Graphics Settings // list Low RenderAnisotropic 1 0 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 0 RenderAvatarPhysicsLODFactor 1 0 RenderAvatarMaxNonImpostors 1 3 @@ -120,297 +100,298 @@ RenderAvatarMaxComplexity 1 35000 RenderFarClip 1 64 RenderFlexTimeFactor 1 0 RenderGlowResolutionPow 1 8 -RenderLocalLights 1 0 +RenderLocalLightCount 1 8 RenderMaxPartCount 1 0 -RenderObjectBump 1 0 -RenderReflectionDetail 1 0 +RenderTransparentWater 1 0 +RenderReflectionsEnabled 1 0 +RenderReflectionProbeDetail 1 0 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 -RenderTransparentWater 1 0 +RenderTerrainPBRDetail 1 -4 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 0 -RenderDeferred 1 0 RenderDeferredSSAO 1 0 -RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 -WLSkyDetail 1 48 +WLSkyDetail 1 96 +RenderFSAAType 1 0 RenderFSAASamples 1 0 +RenderScreenSpaceReflections 1 0 +RenderReflectionProbeLevel 1 0 RenderMirrors 1 0 RenderHeroProbeResolution 1 256 RenderHeroProbeDistance 1 4 -RenderHeroProbeUpdateRate 1 6 +RenderHeroProbeUpdateRate 1 6 RenderHeroProbeConservativeUpdateMultiplier 1 16 +RenderCASSharpness 1 0 RenderExposure 1 1 RenderTonemapType 1 1 RenderTonemapMix 1 0.7 +RenderDisableVintageMode 1 0 +RenderMaxTextureResolution 1 512 +RenderReflectionProbeCount 1 1 // // Medium Low Graphics Settings // list LowMid RenderAnisotropic 1 0 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 0.5 RenderAvatarMaxComplexity 1 100000 RenderAvatarPhysicsLODFactor 1 0.75 +RenderAvatarMaxNonImpostors 1 5 RenderFarClip 1 96 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 8 RenderMaxPartCount 1 2048 -RenderObjectBump 1 1 -RenderLocalLights 1 1 -RenderReflectionDetail 1 0 +RenderLocalLightCount 1 256 +RenderTransparentWater 1 0 +RenderReflectionsEnabled 1 1 +RenderReflectionProbeDetail 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 1.0 -RenderTransparentWater 1 1 +RenderTerrainPBRDetail 1 -1 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 0 -RenderDeferred 1 0 RenderDeferredSSAO 1 0 -RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 -WLSkyDetail 1 48 +WLSkyDetail 1 96 +RenderFSAAType 1 0 RenderFSAASamples 1 0 +RenderScreenSpaceReflections 1 0 +RenderReflectionProbeLevel 1 0 RenderMirrors 1 0 RenderHeroProbeResolution 1 256 RenderHeroProbeDistance 1 6 RenderHeroProbeUpdateRate 1 3 RenderHeroProbeConservativeUpdateMultiplier 1 16 +RenderCASSharpness 1 0 RenderExposure 1 1 RenderTonemapType 1 1 RenderTonemapMix 1 0.7 +RenderDisableVintageMode 1 0 +RenderMaxTextureResolution 1 1024 +RenderReflectionProbeCount 1 32 // // Medium Graphics Settings (standard) // list Mid RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 200000 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 7 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 -RenderLocalLights 1 1 -RenderReflectionDetail 1 0 +RenderLocalLightCount 1 512 +RenderTransparentWater 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 -RenderTransparentWater 1 1 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 -RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 0 +RenderVolumeLODFactor 1 1.25 RenderDeferredSSAO 1 0 -RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 -WLSkyDetail 1 48 -RenderFSAASamples 1 2 +WLSkyDetail 1 96 +RenderFSAAType 1 1 +RenderFSAASamples 1 1 +RenderReflectionsEnabled 1 1 +RenderReflectionProbeDetail 1 0 +RenderScreenSpaceReflections 1 0 +RenderReflectionProbeLevel 1 1 RenderMirrors 1 0 RenderHeroProbeResolution 1 512 RenderHeroProbeDistance 1 6 RenderHeroProbeUpdateRate 1 3 RenderHeroProbeConservativeUpdateMultiplier 1 16 +RenderCASSharpness 1 0 RenderExposure 1 1 RenderTonemapType 1 1 RenderTonemapMix 1 0.7 +RenderMaxTextureResolution 1 2048 +RenderReflectionProbeCount 1 64 // -// Medium High Graphics Settings (deferred enabled) +// Medium High Graphics Settings // list MidHigh RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 250000 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 9 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 -RenderLocalLights 1 1 -RenderReflectionDetail 1 0 +RenderLocalLightCount 1 1024 +RenderTransparentWater 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 -RenderTransparentWater 1 1 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 -RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 1 -RenderUseAdvancedAtmospherics 1 0 +RenderVolumeLODFactor 1 1.375 RenderDeferredSSAO 1 0 RenderShadowDetail 1 0 -WLSkyDetail 1 48 -RenderFSAASamples 1 2 +WLSkyDetail 1 96 +RenderFSAAType 1 1 +RenderFSAASamples 1 1 +RenderReflectionsEnabled 1 1 +RenderReflectionProbeDetail 1 1 +RenderScreenSpaceReflections 1 0 +RenderReflectionProbeLevel 1 1 RenderMirrors 1 0 RenderHeroProbeResolution 1 512 RenderHeroProbeDistance 1 6 RenderHeroProbeUpdateRate 1 2 RenderHeroProbeConservativeUpdateMultiplier 1 8 +RenderCASSharpness 1 0 RenderExposure 1 1 RenderTonemapType 1 1 RenderTonemapMix 1 0.7 +RenderMaxTextureResolution 1 2048 +RenderReflectionProbeCount 1 64 // -// High Graphics Settings (deferred + SSAO) +// High Graphics Settings (SSAO + sun shadows) // list High RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 300000 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 11 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 -RenderLocalLights 1 1 -RenderReflectionDetail 1 0 +RenderLocalLightCount 1 2048 +RenderTransparentWater 1 1 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 -RenderTransparentWater 1 1 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTreeLODFactor 1 0.5 -RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 1 +RenderVolumeLODFactor 1 1.5 RenderDeferredSSAO 1 1 -RenderUseAdvancedAtmospherics 1 0 -RenderShadowDetail 1 0 -WLSkyDetail 1 48 +RenderShadowDetail 1 1 +WLSkyDetail 1 96 +RenderFSAAType 1 2 RenderFSAASamples 1 2 +RenderReflectionsEnabled 1 1 +RenderReflectionProbeDetail 1 1 +RenderScreenSpaceReflections 1 0 +RenderReflectionProbeLevel 1 2 RenderMirrors 1 0 RenderHeroProbeResolution 1 512 RenderHeroProbeDistance 1 8 RenderHeroProbeUpdateRate 1 2 RenderHeroProbeConservativeUpdateMultiplier 1 8 +RenderCASSharpness 1 0.4 RenderExposure 1 1 RenderTonemapType 1 1 RenderTonemapMix 1 0.7 +RenderMaxTextureResolution 1 2048 +RenderReflectionProbeCount 1 128 // -// High Ultra Graphics Settings (deferred + SSAO + shadows) +// High Ultra Graphics Settings (deferred + SSAO + all shadows) // list HighUltra RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 350000 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 16 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 -RenderLocalLights 1 1 -RenderReflectionDetail 1 0 +RenderLocalLightCount 1 4096 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 -RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 1 +RenderVolumeLODFactor 1 1.75 RenderDeferredSSAO 1 1 -RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 -WLSkyDetail 1 48 +WLSkyDetail 1 96 +RenderFSAAType 1 2 RenderFSAASamples 1 2 +RenderReflectionsEnabled 1 1 +RenderReflectionProbeDetail 1 1 +RenderScreenSpaceReflections 1 0 +RenderReflectionProbeLevel 1 3 RenderMirrors 1 0 -RenderHeroProbeResolution 1 512 +RenderHeroProbeResolution 1 1024 RenderHeroProbeDistance 1 16 RenderHeroProbeUpdateRate 1 1 RenderHeroProbeConservativeUpdateMultiplier 1 4 +RenderCASSharpness 1 0.4 RenderExposure 1 1 RenderTonemapType 1 1 RenderTonemapMix 1 0.7 +RenderMaxTextureResolution 1 2048 +RenderReflectionProbeCount 1 256 // // Ultra graphics (REALLY PURTY!) // list Ultra RenderAnisotropic 1 1 -RenderAvatarCloth 1 1 RenderAvatarLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 16 RenderAvatarPhysicsLODFactor 1 1.0 RenderFarClip 1 256 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 -RenderLocalLights 1 1 +RenderLocalLightCount 1 8192 RenderMaxPartCount 1 8192 -RenderObjectBump 1 1 -RenderReflectionDetail 1 4 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 2.0 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 -RenderDeferred 1 1 RenderDeferredSSAO 1 1 -RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 -RenderFSAASamples 1 2 +RenderFSAAType 1 2 +RenderFSAASamples 1 3 +RenderReflectionsEnabled 1 1 +RenderReflectionProbeDetail 1 1 +RenderScreenSpaceReflections 1 0 +RenderReflectionProbeLevel 1 3 RenderMirrors 1 0 -RenderHeroProbeResolution 1 1024 +RenderHeroProbeResolution 1 2048 RenderHeroProbeDistance 1 16 RenderHeroProbeUpdateRate 1 1 RenderHeroProbeConservativeUpdateMultiplier 1 4 +RenderCASSharpness 1 0.4 RenderExposure 1 1 RenderTonemapType 1 1 RenderTonemapMix 1 0.7 +RenderMaxTextureResolution 1 2048 +RenderReflectionProbeCount 1 256 // // Class Unknown Hardware (unknown) // list Unknown -RenderVBOEnable 1 0 RenderShadowDetail 1 0 -RenderDeferred 1 0 RenderDeferredSSAO 1 0 -RenderUseAdvancedAtmospherics 1 0 - -// -// Class 0 Hardware (just old) -// -list Class0 -RenderVBOEnable 1 1 - -// -// Class 1 Hardware -// -list Class1 -RenderVBOEnable 1 1 - -// -// Class 2 Hardware -// -list Class2 -RenderVBOEnable 1 1 - -// -// Class 3 Hardware -// -list Class3 -RenderVBOEnable 1 1 - -// -// Class 4 Hardware -// -list Class4 -RenderVBOEnable 1 1 - -// -// Class 5 Hardware -// -list Class5 -RenderVBOEnable 1 1 +RenderMirrors 1 0 +RenderDisableVintageMode 1 0 // // VRAM > 512MB @@ -418,340 +399,53 @@ RenderVBOEnable 1 1 list VRAMGT512 RenderCompressTextures 1 0 -// -// No Pixel Shaders available -// -list NoPixelShaders -RenderAvatarCloth 0 0 -RenderReflectionDetail 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 -RenderDeferredSSAO 0 0 -RenderUseAdvancedAtmospherics 0 0 -RenderShadowDetail 0 0 - -// -// No Vertex Shaders available -// -list NoVertexShaders -RenderAvatarCloth 0 0 -RenderReflectionDetail 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 -RenderDeferredSSAO 0 0 -RenderUseAdvancedAtmospherics 0 0 -RenderShadowDetail 0 0 - -// -// GL_ARB_map_buffer_range exists -// -list MapBufferRange -RenderVBOMappingDisable 1 1 - - // // "Default" setups for safe, low, medium, high // list safe RenderAnisotropic 1 0 -RenderAvatarCloth 0 0 RenderAvatarMaxNonImpostors 1 16 RenderAvatarMaxComplexity 1 80000 -RenderObjectBump 0 0 -RenderLocalLights 1 0 +RenderLocalLightCount 1 0 RenderMaxPartCount 1 1024 RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -RenderReflectionDetail 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 +RenderTransparentWater 1 0 RenderDeferredSSAO 0 0 -RenderUseAdvancedAtmospherics 0 0 RenderShadowDetail 0 0 - -// -// CPU based feature masks -// - -// 1Ghz or less (equiv) -list CPUSlow -RenderMaxPartCount 1 1024 - -// -// RAM based feature masks -// -list RAM256MB -RenderObjectBump 0 0 - -// -// Graphics card based feature masks -// -list OpenGLPre15 -RenderVBOEnable 1 0 - -list OpenGLPre30 -RenderDeferred 0 0 -RenderMaxTextureIndex 1 1 +RenderReflectionProbeDetail 0 -1 +RenderMirrors 0 0 +RenderDisableVintageMode 1 0 +RenderMaxTextureResolution 1 2048 +RenderReflectionProbeCount 0 0 list Intel RenderAnisotropic 1 0 -// Avoid some Intel crashes on Linux -RenderCubeMap 0 0 +RenderFSAAType 1 0 RenderFSAASamples 1 0 - -list GeForce2 -RenderAnisotropic 1 0 -RenderMaxPartCount 1 2048 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 1 - -list SiS -UseOcclusion 0 0 - - -list Intel_830M -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_845G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_855GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_865G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_900 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_915GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_915G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_945GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_945G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_950 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_965 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -UseOcclusion 0 0 - -list Intel_G33 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Bear_Lake -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Broadwater -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Brookdale -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Montara -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Springdale -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - - -list ATI_FireGL_5200 -RenderVBOEnable 1 0 -WindLightUseAtmosShaders 0 0 - - -list ATI_Mobility_Radeon_7xxx -RenderVBOEnable 0 0 - -list ATI_Radeon_7xxx -RenderVBOEnable 0 0 - -list ATI_All-in-Wonder_Radeon -RenderVBOEnable 0 0 - -list ATI_All-in-Wonder_7500 -RenderVBOEnable 0 0 - -list ATI_Mobility_Radeon_9600 -Disregard96DefaultDrawDistance 1 0 - - -/// tweaked ATI to 96 Draw distance - -list ATI_Radeon_9000 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9200 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9500 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9600 -Disregard96DefaultDrawDistance 1 0 - -/// tweaked ATI to 128 draw distance - -list ATI_Radeon_X300 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X400 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X500 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X600 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X700 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X1300 -Disregard128DefaultDrawDistance 1 0 -UseStartScreen 0 0 -list ATI_Radeon_X1400 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X1500 -Disregard128DefaultDrawDistance 1 0 -UseStartScreen 0 0 -list ATI_Radeon_X1600 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X1700 -Disregard128DefaultDrawDistance 1 0 -list ATI_Mobility_Radeon_X1xxx -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_HD_2300 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_HD_2400 -Disregard128DefaultDrawDistance 1 0 -list ATI_ASUS_AH24xx -Disregard128DefaultDrawDistance 1 0 - - -// Avatar hardware skinning causes invisible avatars -// on various ATI chipsets on drivers before 8.2 - -list ATIOldDriver -RenderAvatarCloth 0 0 -// Avoid driver crashes with some features on Linux with old ATI drivers -UseOcclusion 0 0 -WindLightUseAtmosShaders 0 0 - - -/// Tweaked NVIDIA - -list NVIDIA_GeForce_FX_5100 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_5200 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_5500 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_5600 -Disregard96DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_FX_Go5100 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5200 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5300 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5500 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5600 -Disregard96DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_6100 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6200 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6500 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6600 -Disregard128DefaultDrawDistance 1 0 - -list NVIDIA_G73 -Disregard128DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_Go_6100 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6200 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6500 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6600 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6700 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6800 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_7000 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7100 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7200 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7300 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7400 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7500 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7600 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7700 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7800 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7900 -RenderShaderLightingMaxLevel 1 2 - -list NVIDIA_GeForce_Go_7200 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7300 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7300_LE -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7400 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7600 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7700 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7800 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7900 -RenderShaderLightingMaxLevel 1 2 +RenderGLContextCoreProfile 1 0 +RenderGLMultiThreadedMedia 1 0 +RenderDownScaleMethod 1 0 + +list AMD +RenderGLMultiThreadedTextures 1 0 + +list NVIDIA +RenderGLMultiThreadedMedia 1 1 + +list GL3 +RenderFSAAType 0 0 +RenderFSAASamples 0 0 +RenderReflectionsEnabled 0 0 +RenderReflectionProbeDetail 0 0 +RenderMirrors 0 0 +RenderGLMultiThreadedTextures 0 0 +RenderGLMultiThreadedMedia 0 0 +RenderDisableVintageMode 1 0 +RenderReflectionProbeCount 0 0 + +list TexUnit16orLess +RenderTerrainPBRDetail 1 -1 + +list VaryingVectors16orLess +RenderTerrainPBRPlanarSampleCount 1 1 diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp index 4f8f80129d9..12bd5661d20 100644 --- a/indra/newview/gltf/llgltfloader.cpp +++ b/indra/newview/gltf/llgltfloader.cpp @@ -489,7 +489,7 @@ void LLGLTFLoader::processNodeHierarchy(S32 node_idx, std::map } else { - setLoadState(ERROR_MODEL + pModel->getStatus()); + setLoadState(static_cast(ERROR_MODEL) + static_cast(pModel->getStatus())); delete pModel; return; } diff --git a/indra/newview/linux_tools/client-readme-joystick.txt b/indra/newview/linux_tools/client-readme-joystick.txt deleted file mode 100644 index 4f89a73ccbe..00000000000 --- a/indra/newview/linux_tools/client-readme-joystick.txt +++ /dev/null @@ -1,78 +0,0 @@ -Second Life - Joystick & SpaceNavigator Support README --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - -WHAT IS IT? --=-=-=-=-=- - -This feature allows the use of a joystick or other supported multi-axis -device for controlling your avatar and camera. - -REQUIREMENTS --=-=-=-=-=-= - -* A joystick or other generic multi-axis input device supported by your chosen - version of Linux - -- OR - - -* A SpaceNavigator device (additional configuration may be required, see below) - -Success has been reported on the following systems so far: -* Ubuntu 7.04 (Feisty) with a generic USB joystick -* Ubuntu 7.04 (Feisty) with a USB 3DConnexion SpaceNavigator -* Ubuntu 6.06 (Dapper) with a generic USB joystick -* Ubuntu 6.06 (Dapper) with a USB 3DConnexion SpaceNavigator - -CONFIGURATION --=-=-=-=-=-=- - -SPACE NAVIGATOR: *Important* - do not install the Linux SpaceNavigator -drivers from the disk included with the device - these are problematic. -Some distributions of Linux (such as Ubuntu, Gentoo and Mandriva) will -need some system configuration to make the SpaceNavigator usable by -applications such as the Second Life Viewer, as follows: - -* Mandriva Linux Configuration: - You need to add two new files to your system. This only needs to be - done once. These files are available at the 'SpaceNavigator support with - udev and Linux input framework' section of - - -* Ubuntu or Gentoo Linux Configuration: - For a quick start, you can simply paste the following line into a terminal - before plugging in your SpaceNavigator - this only needs to be done once: - sudo bash -c 'echo KERNEL==\"event[0-9]*\", SYSFS{idVendor}==\"046d\", SYSFS{idProduct}==\"c626\", SYMLINK+=\"input/spacenavigator\", GROUP=\"plugdev\", MODE=\"664\" > /etc/udev/rules.d/91-spacenavigator-LL.rules ; echo "" > /etc/hal/fdi/policy/3Dconnexion_SpaceNavigator_LL.fdi' - -For more comprehensive Linux SpaceNavigator configuration information please -see the section 'Installing SpaceNavigator without the official driver' here: - - -JOYSTICKS: These should be automatically detected and configured on all -modern distributions of Linux. - -ALL: Your joystick or SpaceNavigator should be plugged-in before you start the -Second Life Viewer, so that it may be detected. If you have multiple input -devices attached, only the first detected SpaceNavigator or joystick device -will be available. - -Once your system recognises your joystick or SpaceNavigator correctly, you -can go into the Second Life Viewer's Preferences dialog, click the 'Input & -Camera' tab, and click the 'Joystick Setup' button. From here you may enable -and disable joystick support and change some configuration settings such as -sensitivity. SpaceNavigator users are recommended to click the -'SpaceNavigator Defaults' button. - -KNOWN PROBLEMS --=-=-=-=-=-=-= - -* If your chosen version of Linux treats your joystick/SpaceNavigator as -if it were a mouse when you plug it in (i.e. it is automatically used to control -your desktop cursor), then the SL Viewer may detect this device *but* will be -unable to use it properly. - -FURTHER PROBLEMS? --=-=-=-=-=-=-=-=- - -Please report further issues to the public Second Life issue-tracker -at (please note, however, that this is not -a support forum). diff --git a/indra/newview/linux_tools/client-readme-voice.txt b/indra/newview/linux_tools/client-readme-voice.txt deleted file mode 100644 index bfefdf3471b..00000000000 --- a/indra/newview/linux_tools/client-readme-voice.txt +++ /dev/null @@ -1,81 +0,0 @@ -Second Life - Linux Voice Support README --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - -WHAT IS IT? --=-=-=-=-=- - -Linux Voice Support is a feature in testing which allows users of the Linux -Second Life client to participate in voice-chat with other residents and -groups inside Second Life, with an appropriate headset/microphone. - -REQUIREMENTS --=-=-=-=-=-= - -* A headset/microphone supported by your chosen version of Linux -* At this time, the PulseAudio audio system is recommended; this software - is already part of most modern (2009+) Linux desktop systems. Alternatively, - the ALSA audio system may be used on systems installed from around - 2007 onwards (again this is likely already installed on your system). - -TESTING YOUR SETTINGS --=-=-=-=-=-=-=-=-=-=- - -* The Second Life region 'Voice Echo Canyon' is a great place for testing -your hardware settings and quality - it will 'echo' your voice back to you -when you speak. - -KNOWN PROBLEMS --=-=-=-=-=-=-= - -* Compatibility with old ALSA-based audio systems (such as Ubuntu Dapper - from 2006) is poor. - -TROUBLESHOOTING --=-=-=-=-=-=-=- - -PROBLEM 1: I don't see a white dot over the head of my avatar or other - Voice-using avatars. -SOLUTION: -a. Ensure that 'Enable voice' is enabled in the 'Sound' section of the - Preferences window, and that you are in a voice-enabled area. -b. If the above does not help, exit Second Life and ensure that any - remaining 'SLVoice' processes (as reported by 'ps', 'top' or similar) - are killed before restarting. - -PROBLEM 2: I have a white dot over my head but I never see (or hear!) anyone - except myself listed in the Active Speakers dialog when I'm sure that other - residents nearby are active Voice users. -SOLUTION: This is an incompatibility between the Voice support and your - system's audio (ALSA) driver version/configuration. -a. Back-up and remove your ~/.asoundrc file, re-test. -b. Check for updates to your kernel, kernel modules and ALSA-related - packages using your Linux distribution's package-manager - install these, - reboot and re-test. -c. Update to the latest version of ALSA manually. For a guide, see the - 'Update to the Latest Version of ALSA' section of this page: - or the official - documentation on the ALSA site: - reboot - and re-test. - -PROBLEM 3: I can hear other people, but they cannot hear me. -SOLUTION: -a. Ensure that you have the 'Speak' button (at the bottom of the Second Life - window) activated while you are trying to speak. -b. Ensure that your microphone jack is inserted into the correct socket of your - sound card, where appropriate. -c. Use your system mixer-setting program (such as the PulseAudio 'volume - control' applet or the ALSA 'alsamixer' program) to ensure that microphone - input is set as the active input source and is not muted. -d. Verify that audio input works in other applications, i.e. Audacity - -PROBLEM 4: Other people just hear bursts of loud noise when I speak. -SOLUTION: -a. Use your system mixer-setting program or the 'alsamixer' program to ensure - that microphone Gain/Boost is not set too high. - -FURTHER PROBLEMS? --=-=-=-=-=-=-=-=- - -Please report further issues to the public Second Life issue-tracker -at (please note, however, that this is not -a support forum). diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt deleted file mode 100644 index cb8d1af5358..00000000000 --- a/indra/newview/linux_tools/client-readme.txt +++ /dev/null @@ -1,244 +0,0 @@ -Second Life - Linux Beta README --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -This document contains information about the Second Life Linux -client, and isn't meant to serve as an introduction to Second -Life itself - please see . - -1. Introduction -2. System Requirements -3. Installing & Running -4. Known Issues -5. Troubleshooting - 5.1. 'Error creating window.' - 5.2. System hangs - 5.3. Blank window after minimizing it - 5.4. Audio - 5.5. 'Alt' key for camera controls doesn't work - 5.6. In-world streaming movie, music and Flash playback -6. Advanced Troubleshooting - 6.1. Audio - 6.2. OpenGL -7. Obtaining and working with the client source code -8. Getting more help, and reporting problems - - -1. INTRODUCTION --=-=-=-=-=-=-=- - -Hi! This is a BETA release of the Second Life client for Linux. -The 'beta' status means that although we're still smoothing-out a few rough -edges, this version of the client is functionally complete and should -work quite well 'out of the box' for accessing Second Life. - -We encourage you to try it out and let us know of its compatibility -with your system. Be aware that although this is a 'beta' client, it connects -to the main Second Life world and changes you make there are permanent. - -You will have either obtained this client from secondlife.com (the official -site) or from a third-party packager; if you encounter any problems then -we recommend trying the latest official builds from secondlife.com which are -updated often. - -Please enjoy! - - -2. SYSTEM REQUIREMENTS --=-=-=-=-=-=-=-=-=-=-= - -Minimum requirements: - * Internet Connection: Cable or DSL - * Computer Processor: 800MHz Pentium III or Athlon or better - (recommended: 1.5GHz or more) - * Computer Memory: 512MB (recommended: 768MB or more) - * Linux Operating System: A reasonably modern 32-bit Linux environment - is required. If you are running a 64-bit Linux distribution then - you will need its 32-bit compatibility environment installed, but - this configuration is not currently supported. - * PulseAudio or ALSA Linux system sound software. A recent PulseAudio - is the recommended configuration; see README-linux-voice.txt for more - information. - * Video/Graphics Card: - o nVidia GeForce 2, GeForce 4mx, or better (recommend one of the - following: 6700, 6800, 7600, 7800, 7900, 8400, 8500, 8600, - 8800, Go 7400, Go 7600, Go 7800, Go 7900, +) - o OR ATI Radeon 8500, 9250, or better - (nVidia cards are recommended for the Linux client) - - **NOTE**: Second Life absolutely requires you to have recent, correctly- - configured OpenGL 3D drivers for your hardware - the graphics drivers - that came with your operating system may not be good enough! See the - TROUBLESHOOTING section if you encounter problems starting Second Life. - -For a more comfortable experience, the RECOMMENDED hardware for the Second -Life Linux client is very similar to that for Windows, as detailed at: - - - -3. INSTALLING & RUNNING --=-=-=-=-=-=-=-=-=-=-=- - -The Second Life Linux client can entirely run from the directory you have -unpacked it into - no installation step is required. If you wish to -perform a separate installation step anyway, you may run './install.sh' - -Run ./secondlife from the installation directory to start Second Life. - -For in-world MOVIE and MUSIC PLAYBACK, you will need (32-bit) GStreamer 0.10 -installed on your system. This is optional - it is not required for general -client functionality. If you have GStreamer 0.10 installed, the selection of -in-world movies you can successfully play will depend on the GStreamer -plugins you have; if you cannot play a certain in-world movie then you are -probably missing the appropriate GStreamer plugin on your system - you may -be able to install it (see TROUBLESHOOTING). - -User data is stored in the hidden directory ~/.secondlife by default; you may -override this location with the SECONDLIFE_USER_DIR environment variable if -you wish. - - -4. KNOWN ISSUES --=-=-=-=-=-=-=- - -* No significant known issues at this time. - - -5. TROUBLESHOOTING --=-=-=-=-=-=-=-=-= - -The client prints a lot of diagnostic information to the console it was -run from. Most of this is also replicated in ~/.secondlife/logs/SecondLife.log -- this is helpful to read when troubleshooting, especially 'WARNING' and -'ERROR' lines. - -VOICE PROBLEMS? See the separate README-linux-voice.txt file for Voice - troubleshooting information. - -SPACENAVIGATOR OR JOYSTICK PROBLEMS? See the separate - README-linux-joystick.txt file for configuration information. - -PROBLEM 1:- Second Life fails to start up, with a warning on the console like: - 'Error creating window.' or - 'Unable to create window, be sure screen is set at 32-bit color' or - 'SDL: Couldn't find matching GLX visual.' -SOLUTION:- Usually this indicates that your graphics card does not meet - the minimum requirements, or that your system's OpenGL 3D graphics driver is - not updated and configured correctly. If you believe that your graphics - card DOES meet the minimum requirements then you likely need to install the - official so-called 'non-free' nVidia or ATI (fglrx) graphics drivers; we - suggest one of the following options: - * Consult your Linux distribution's documentation for installing these - official drivers. For example, Ubuntu provides documentation here: - - * If your distribution does not make it easy, then you can download the - required Linux drivers straight from your graphics card manufacturer: - - nVidia cards: - - ATI cards: - -PROBLEM 2:- My whole system seems to hang when running Second Life. -SOLUTION:- This is typically a hardware/driver issue. The first thing to - do is to check that you have the most recent official drivers for your - graphics card (see PROBLEM 1). -SOLUTION:- Some residents with ATI cards have reported that running - 'sudo aticonfig --locked-userpages=off' before running Second Life solves - their stability issues. -SOLUTION:- As a last resort, you can disable most of Second Life's advanced - graphics features by editing the 'secondlife' script and removing the '#' - from the line which reads '#export LL_GL_NOEXT=x' - -PROBLEM 3:- After I minimize the Second Life window, it's just blank when - it comes back. -SOLUTION:- Some Linux desktop 'Visual Effects' features are incompatible - with Second Life. One reported solution is to use your desktop - configuration program to disable such effects. For example, on Ubuntu 7.10, - use the desktop toolbar menu to select System -> Preferences -> Appearance, - then change 'Visual Effects' to 'None'. - -PROBLEM 4:- Music and sound effects are silent or very stuttery. -SOLUTION:- The most common solution is to ensure that you have the 'esd' - program (part of the 'esound' package) installed and running before you - start Second Life. Users of Ubuntu (and some other) Linux systems can - simply run the following to install and configure 'esound': - sudo apt-get install esound - For others, simply running 'esd&' from a command-line should get it running. - -PROBLEM 5:- Using the 'Alt' key to control the camera doesn't work or just - moves the Second Life window. -SOLUTION:- Some window managers eat the Alt key for their own purposes; you - can configure your window manager to use a different key instead (for - example, the 'Windows' key!) which will allow the Alt key to function - properly with mouse actions in Second Life and other applications. - -PROBLEM 6:- In-world movie, music, or Flash playback doesn't work for me. -SOLUTION:- You need to have a working installation of GStreamer 0.10; this - is usually an optional package for most versions of Linux. If you have - installed GStreamer 0.10 and you can play some music/movies but not others - then you need to install a wider selection of GStreamer plugins, either - from your vendor (i.e. the 'Ugly' plugins) or an appropriate third party. - For Flash playback, you need to have Flash 10 installed for your normal - web browser (for example, Firefox). PulseAudio is required for Flash - volume control / muting to fully function inside Second Life. - - -6. ADVANCED TROUBLESHOOTING --=-=-=-=-=-=-=-=-=-=-=-=-=- - -The 'secondlife' script which launches Second Life contains some -configuration options for advanced troubleshooters. - -* AUDIO - Edit the 'secondlife' script and you will see these audio - options: LL_BAD_OPENAL_DRIVER, LL_BAD_FMODSTUDIO_DRIVER. - Second Life tries to use OpenAL, FMODSTUDIO (PULSEAUDIO, ALSA) - audio drivers in this order; you may uncomment the corresponding LL_BAD_* - option to skip an audio driver which you believe may be causing you trouble. - -* OPENGL - For advanced troubleshooters, the LL_GL_BLACKLIST option lets - you disable specific GL extensions, each of which is represented by a - letter ("a"-"o"). If you can narrow down a stability problem on your system - to just one or two GL extensions then please post details of your hardware - (and drivers) to the Linux Client Testers forum (see link below) along - with the minimal LL_GL_BLACKLIST which solves your problems. This will help - us to improve stability for your hardware while minimally impacting - performance. - LL_GL_BASICEXT and LL_GL_NOEXT should be commented-out for this to be useful. - - -7. OBTAINING AND WORKING WITH THE CLIENT SOURCE CODE --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - -We're pleased to have released the Second Life client's source code under -an Open Source license compatible with the 'GPL'. To get involved with client -development, please see: - - - -8. GETTING MORE HELP AND REPORTING PROBLEMS --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -For general help and support with Second Life: - - -For problems and discussion concerning unofficial (not secondlife.com) -releases, please contact your packager or the SLDev mailing list: - - -In-world help: Please use the 'Help' menu in the client for various -non-Linux-specific Second Life help options. - -In-world discussion: There is a 'Linux Client Users' group -inside Second Life which is free to join. You can find it by pressing -the 'Search' button at the bottom of the window and then selecting the -'Groups' tab and searching for 'Linux'. This group is useful for discussing -Linux issues with fellow Linux client users who are online. - -The Second Life Issue Tracker: - -This is the right place for finding known issues and reporting new -bugs in all Second Life releases if you find that the Troubleshooting -section in this file hasn't helped (please note, however, that this is -not a support forum). - -Linux Client Testers forum: - -This is a forum where Linux Client users can help each other out and -discuss the latest updates. diff --git a/indra/newview/linux_tools/refresh_desktop_app_entry.sh b/indra/newview/linux_tools/refresh_desktop_app_entry.sh index d2b2a732d54..be3622c3c9d 100755 --- a/indra/newview/linux_tools/refresh_desktop_app_entry.sh +++ b/indra/newview/linux_tools/refresh_desktop_app_entry.sh @@ -3,7 +3,7 @@ SCRIPTSRC=`readlink -f "$0" || echo "$0"` RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` -install_prefix=${RUN_PATH}/.. +install_prefix="$(realpath -- "${RUN_PATH}/..")" function install_desktop_entry() { @@ -13,18 +13,25 @@ function install_desktop_entry() local desktop_entry="\ [Desktop Entry]\n\ Name=Second Life\n\ +GenericName=Second Life Viewer\n\ Comment=Client for the On-line Virtual World, Second Life\n\ -Exec=${installation_prefix}/secondlife\n\ +Path=${installation_prefix}\n\ +Exec=secondlife\n\ Icon=${installation_prefix}/secondlife_icon.png\n\ Terminal=false\n\ Type=Application\n\ -Categories=Application;Network;\n\ +Categories=Game;Simulation;\n\ StartupNotify=true\n\ +StartupWMClass="SecondLife"\n\ X-Desktop-File-Install-Version=3.0" echo " - Installing menu entries in ${desktop_entries_dir}" - mkdir -vp "${desktop_entries_dir}" - echo -e $desktop_entry > "${desktop_entries_dir}/secondlife-viewer.desktop" || "Failed to install application menu!" + WORK_DIR=`mktemp -d` + echo -e $desktop_entry > "${WORK_DIR}/secondlife-viewer.desktop" || "Failed to install application menu!" + desktop-file-install --dir="${desktop_entries_dir}" ${WORK_DIR}/secondlife-viewer.desktop + rm -r $WORK_DIR + + update-desktop-database "${desktop_entries_dir}" } if [ "$UID" == "0" ]; then diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index eb3ead433b7..258691bd5fb 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -1,48 +1,12 @@ #!/bin/bash -## Here are some configuration options for Linux Client Testers. -## These options are for self-assisted troubleshooting during this beta -## testing phase; you should not usually need to touch them. +## Here are some configuration options for Linux Client Users. -## - Avoids using any FMOD STUDIO audio driver. -#export LL_BAD_FMODSTUDIO_DRIVER=x ## - Avoids using any OpenAL audio driver. #export LL_BAD_OPENAL_DRIVER=x -## - Avoids using the FMOD Studio or FMOD Ex PulseAudio audio driver. -#export LL_BAD_FMOD_PULSEAUDIO=x -## - Avoids using the FMOD Studio or FMOD Ex ALSA audio driver. -#export LL_BAD_FMOD_ALSA=x - -## - Avoids the optional OpenGL extensions which have proven most problematic -## on some hardware. Disabling this option may cause BETTER PERFORMANCE but -## may also cause CRASHES and hangs on some unstable combinations of drivers -## and hardware. -## NOTE: This is now disabled by default. -#export LL_GL_BASICEXT=x - -## - Avoids *all* optional OpenGL extensions. This is the safest and least- -## exciting option. Enable this if you experience stability issues, and -## report whether it helps in the Linux Client Testers forum. -#export LL_GL_NOEXT=x - -## - For advanced troubleshooters, this lets you disable specific GL -## extensions, each of which is represented by a letter a-o. If you can -## narrow down a stability problem on your system to just one or two -## extensions then please post details of your hardware (and drivers) to -## the Linux Client Testers forum along with the minimal -## LL_GL_BLACKLIST which solves your problems. -#export LL_GL_BLACKLIST=abcdefghijklmno - -## - Some ATI/Radeon users report random X server crashes when the mouse -## cursor changes shape. If you suspect that you are a victim of this -## driver bug, try enabling this option and report whether it helps: -#export LL_ATI_MOUSE_CURSOR_BUG=x - -if [ "`uname -m`" = "x86_64" ]; then - echo '64-bit Linux detected.' -fi - +## GL Driver Options +export mesa_glthread=true ## Everything below this line is just for advanced troubleshooters. ##------------------------------------------------------------------- @@ -55,32 +19,6 @@ fi #export LL_WRAPPER='gdb --args' #export LL_WRAPPER='valgrind --smc-check=all --error-limit=no --log-file=secondlife.vg --leak-check=full --suppressions=/usr/lib/valgrind/glibc-2.5.supp --suppressions=secondlife-i686.supp' -## - Avoids an often-buggy X feature that doesn't really benefit us anyway. -export SDL_VIDEO_X11_DGAMOUSE=0 - -## - Works around a problem with misconfigured 64-bit systems not finding GL -I386_MULTIARCH="$(dpkg-architecture -ai386 -qDEB_HOST_MULTIARCH 2>/dev/null)" -MULTIARCH_ERR=$? -if [ $MULTIARCH_ERR -eq 0 ]; then - echo 'Multi-arch support detected.' - MULTIARCH_GL_DRIVERS="/usr/lib/${I386_MULTIARCH}/dri" - export LIBGL_DRIVERS_PATH="${LIBGL_DRIVERS_PATH}:${MULTIARCH_GL_DRIVERS}:/usr/lib64/dri:/usr/lib32/dri:/usr/lib/dri" -else - export LIBGL_DRIVERS_PATH="${LIBGL_DRIVERS_PATH}:/usr/lib64/dri:/usr/lib32/dri:/usr/lib/dri" -fi - -## - The 'scim' GTK IM module widely crashes the viewer. Avoid it. -if [ "$GTK_IM_MODULE" = "scim" ]; then - export GTK_IM_MODULE=xim -fi - -## - Automatically work around the ATI mouse cursor crash bug: -## (this workaround is disabled as most fglrx users do not see the bug) -#if lsmod | grep fglrx &>/dev/null ; then -# export LL_ATI_MOUSE_CURSOR_BUG=x -#fi - - ## Nothing worth editing below this line. ##------------------------------------------------------------------- @@ -89,6 +27,8 @@ RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` echo "Running from ${RUN_PATH}" cd "${RUN_PATH}" +export SDL_APP_ID="SecondLife" + # Re-register the secondlife:// protocol handler every launch, for now. ./etc/register_secondlifeprotocol.sh @@ -99,24 +39,7 @@ cd "${RUN_PATH}" ## subprocesses that care. export SAVED_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" -# if [ -n "$LL_TCMALLOC" ]; then -# tcmalloc_libs='/usr/lib/libtcmalloc.so.0 /usr/lib/libstacktrace.so.0 /lib/libpthread.so.0' -# all=1 -# for f in $tcmalloc_libs; do -# if [ ! -f $f ]; then -# all=0 -# fi -# done -# if [ $all != 1 ]; then -# echo 'Cannot use tcmalloc libraries: components missing' 1>&2 -# else -# export LD_PRELOAD=$(echo $tcmalloc_libs | tr ' ' :) -# if [ -z "$HEAPCHECK" -a -z "$HEAPPROFILE" ]; then -# export HEAPCHECK=${HEAPCHECK:-normal} -# fi -# fi -#fi - +# Add our library directory export LD_LIBRARY_PATH="$PWD/lib:${LD_LIBRARY_PATH}" # Copy "$@" to ARGS array specifically to delete the --skip-gridargs switch. @@ -140,23 +63,4 @@ LL_RUN_ERR=$? if [ $LL_RUN_ERR -ne 0 ]; then # generic error running the binary echo '*** Bad shutdown ($LL_RUN_ERR). ***' - if [ "$(uname -m)" = "x86_64" ]; then - echo - cat << EOFMARKER -You are running the Second Life Viewer on a x86_64 platform. The -most common problems when launching the Viewer (particularly -'bin/do-not-directly-run-secondlife-bin: not found' and 'error while -loading shared libraries') may be solved by installing your Linux -distribution's 32-bit compatibility packages. -For example, on Ubuntu and other Debian-based Linuxes you might run: -$ sudo apt-get install ia32-libs ia32-libs-gtk ia32-libs-kde ia32-libs-sdl -EOFMARKER - fi fi - -echo -echo '*******************************************************' -echo 'This is a BETA release of the Second Life linux client.' -echo 'Thank you for testing!' -echo 'Please see README-linux.txt before reporting problems.' -echo diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index eadc5e7e63f..3a2b8690e44 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -131,15 +131,17 @@ #include "stringize.h" #include "llcoros.h" #include "llexception.h" -#if !LL_LINUX #include "cef/dullahan_version.h" #include "vlc/libvlc_version.h" -#endif // LL_LINUX #if LL_DARWIN #include "llwindowmacosx.h" #endif +#if LL_SDL_WINDOW +#include "llwindowsdl.h" +#endif + // Third party library includes #include #include @@ -180,7 +182,6 @@ #include "lltracker.h" #include "llviewerparcelmgr.h" #include "llworldmapview.h" -#include "llpostprocess.h" #include "lldebugview.h" #include "llconsole.h" @@ -264,10 +265,6 @@ using namespace LL; // define a self-registering event API object #include "llappviewerlistener.h" -#if LL_LINUX && LL_GTK -#include "glib.h" -#endif // (LL_LINUX) && LL_GTK - #ifdef LL_DISCORD #define DISCORDPP_IMPLEMENTATION #include @@ -1113,7 +1110,7 @@ bool LLAppViewer::init() gGLActive = false; -#if LL_RELEASE_FOR_DOWNLOAD +#if LL_RELEASE_FOR_DOWNLOAD && !LL_LINUX // Skip updater if this is a non-interactive instance if (!gSavedSettings.getBOOL("CmdLineSkipUpdater") && !gNonInteractive) { @@ -1171,10 +1168,11 @@ bool LLAppViewer::init() } } else +#endif //LL_RELEASE_FOR_DOWNLOAD { + mUpdaterNotFound = true; LL_WARNS("InitInfo") << "Skipping updater check." << LL_ENDL; } -#endif //LL_RELEASE_FOR_DOWNLOAD { // Iterate over --leap command-line options. But this is a bit tricky: if @@ -1347,6 +1345,8 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { + LL_RECORD_BLOCK_TIME(FTM_FRAME); + LL_PROFILE_GPU_ZONE("Frame"); #ifdef LL_DISCORD { LL_PROFILE_ZONE_NAMED("discord_callbacks"); @@ -1354,8 +1354,6 @@ bool LLAppViewer::doFrame() } #endif - LL_RECORD_BLOCK_TIME(FTM_FRAME); - LL_PROFILE_GPU_ZONE("Frame"); { // and now adjust the visuals from previous frame. if(LLPerfStats::tunables.userAutoTuneEnabled && LLPerfStats::tunables.tuningFlag != LLPerfStats::Tunables::Nothing) @@ -1879,8 +1877,6 @@ bool LLAppViewer::cleanup() SUBSYSTEM_CLEANUP(LLAvatarAppearance); - SUBSYSTEM_CLEANUP(LLPostProcess); - LLTracker::cleanupInstance(); // *FIX: This is handled in LLAppViewerWin32::cleanup(). @@ -3418,7 +3414,6 @@ LLSD LLAppViewer::getViewerInfo() const info["VOICE_VERSION"] = LLTrans::getString("NotConnected"); } -#if !LL_LINUX std::ostringstream cef_ver_codec; cef_ver_codec << "Dullahan: "; cef_ver_codec << DULLAHAN_VERSION_MAJOR; @@ -3444,11 +3439,7 @@ LLSD LLAppViewer::getViewerInfo() const cef_ver_codec << CHROME_VERSION_PATCH; info["LIBCEF_VERSION"] = cef_ver_codec.str(); -#else - info["LIBCEF_VERSION"] = "Undefined"; -#endif -#if !LL_LINUX std::ostringstream vlc_ver_codec; vlc_ver_codec << LIBVLC_VERSION_MAJOR; vlc_ver_codec << "."; @@ -3456,9 +3447,6 @@ LLSD LLAppViewer::getViewerInfo() const vlc_ver_codec << "."; vlc_ver_codec << LIBVLC_VERSION_REVISION; info["LIBVLC_VERSION"] = vlc_ver_codec.str(); -#else - info["LIBVLC_VERSION"] = "Undefined"; -#endif S32 packets_in = (S32)LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN); if (packets_in > 0) diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 89d19d180b5..2e2dabf1f22 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -34,22 +34,32 @@ #include "llurldispatcher.h" // SLURL from other app instance #include "llviewernetwork.h" #include "llviewercontrol.h" -#include "llwindowsdl.h" #include "llmd5.h" #include "llfindlocale.h" #include +#ifdef LL_GLIB +#include +#endif -#if LL_DBUS_ENABLED -# include "llappviewerlinux_api_dbus.h" +#define VIEWERAPI_SERVICE "com.secondlife.ViewerAppAPIService" +#define VIEWERAPI_PATH "/com/secondlife/ViewerAppAPI" +#define VIEWERAPI_INTERFACE "com.secondlife.ViewerAppAPI" -// regrettable hacks to give us better runtime compatibility with older systems inside llappviewerlinux_api.h: -#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0) -#undef g_return_if_fail -#define g_return_if_fail(COND) llg_return_if_fail(COND) -// The generated API -# include "llappviewerlinux_api.h" -#endif +static const char * DBUS_SERVER = "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; + +typedef struct +{ + GObject parent; +} ViewerAppAPI; namespace { @@ -86,6 +96,8 @@ int main( int argc, char **argv ) // install unexpected exception handler gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler); + unsetenv( "LD_PRELOAD" ); // Get rid of any preloading, we do not want this to happen during startup of plugins. + bool ok = viewer_app_ptr->init(); if(!ok) { @@ -93,7 +105,7 @@ int main( int argc, char **argv ) return -1; } - // Run the application main loop + // Run the application main loop while (! viewer_app_ptr->frame()) {} @@ -121,12 +133,6 @@ LLAppViewerLinux::~LLAppViewerLinux() bool LLAppViewerLinux::init() { - // g_thread_init() must be called before *any* use of glib, *and* - // before any mutexes are held, *and* some of our third-party - // libraries likes to use glib functions; in short, do this here - // really early in app startup! - if (!g_thread_supported ()) g_thread_init (NULL); - bool success = LLAppViewer::init(); #if LL_SEND_CRASH_REPORTS @@ -148,7 +154,7 @@ bool LLAppViewerLinux::restoreErrorTrap() } ///////////////////////////////////////// -#if LL_DBUS_ENABLED +#if LL_GLIB typedef struct { @@ -158,101 +164,77 @@ typedef struct static void viewerappapi_init(ViewerAppAPI *server); static void viewerappapi_class_init(ViewerAppAPIClass *klass); -/// - -// regrettable hacks to give us better runtime compatibility with older systems in general -static GType llg_type_register_static_simple_ONCE(GType parent_type, - const gchar *type_name, - guint class_size, - GClassInitFunc class_init, - guint instance_size, - GInstanceInitFunc instance_init, - GTypeFlags flags) -{ - static GTypeInfo type_info; - memset(&type_info, 0, sizeof(type_info)); - - type_info.class_size = class_size; - type_info.class_init = class_init; - type_info.instance_size = instance_size; - type_info.instance_init = instance_init; - - return g_type_register_static(parent_type, type_name, &type_info, flags); -} -#define llg_intern_static_string(S) (S) -#define g_intern_static_string(S) llg_intern_static_string(S) -#define g_type_register_static_simple(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) llg_type_register_static_simple_ONCE(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) - G_DEFINE_TYPE(ViewerAppAPI, viewerappapi, G_TYPE_OBJECT); void viewerappapi_class_init(ViewerAppAPIClass *klass) { } -static bool dbus_server_init = false; - -void viewerappapi_init(ViewerAppAPI *server) +static void dispatchSLURL(gchar const *slurl) { - // Connect to the default DBUS, register our service/API. - - if (!dbus_server_init) - { - GError *error = NULL; - - server->connection = lldbus_g_bus_get(DBUS_BUS_SESSION, &error); - if (server->connection) - { - lldbus_g_object_type_install_info(viewerappapi_get_type(), &dbus_glib_viewerapp_object_info); + LL_INFOS() << "Was asked to go to slurl: " << slurl << LL_ENDL; - lldbus_g_connection_register_g_object(server->connection, VIEWERAPI_PATH, G_OBJECT(server)); + std::string url = slurl; + LLMediaCtrl* web = NULL; + const bool trusted_browser = false; + LLURLDispatcher::dispatch(url, "", web, trusted_browser); +} - DBusGProxy *serverproxy = lldbus_g_proxy_new_for_name(server->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); +static void DoMethodeCall (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + LL_INFOS() << "DBUS message " << method_name << " from: " << sender << " interface: " << interface_name << LL_ENDL; + const gchar *slurl; - guint request_name_ret_unused; - // akin to org_freedesktop_DBus_request_name - if (lldbus_g_proxy_call(serverproxy, "RequestName", &error, G_TYPE_STRING, VIEWERAPI_SERVICE, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_ret_unused, G_TYPE_INVALID)) - { - // total success. - dbus_server_init = true; - } - else - { - LL_WARNS() << "Unable to register service name: " << error->message << LL_ENDL; - } + g_variant_get (parameters, "(&s)", &slurl); + dispatchSLURL(slurl); +} - g_object_unref(serverproxy); - } - else +GDBusNodeInfo *gBusNodeInfo = nullptr; +static const GDBusInterfaceVTable interface_vtable = { - g_warning("Unable to connect to dbus: %s", error->message); - } - - if (error) - g_error_free(error); - } + DoMethodeCall + }; +static void busAcquired(GDBusConnection *connection, const gchar *name, gpointer user_data) +{ + auto id = g_dbus_connection_register_object(connection, + VIEWERAPI_PATH, + gBusNodeInfo->interfaces[0], + &interface_vtable, + NULL, /* user_data */ + NULL, /* user_data_free_func */ + NULL); /* GError** */ + g_assert (id > 0); } -gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error) +static void nameAcquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { - bool success = false; - - LL_INFOS() << "Was asked to go to slurl: " << slurl << LL_ENDL; +} - std::string url = slurl; - LLMediaCtrl* web = NULL; - const bool trusted_browser = false; - if (LLURLDispatcher::dispatch(url, "", web, trusted_browser)) - { - // bring window to foreground, as it has just been "launched" from a URL - // todo: hmm, how to get there from here? - //xxx->mWindow->bringToFront(); - success = true; - } +static void nameLost(GDBusConnection *connection, const gchar *name, gpointer user_data) +{ - *success_rtn = g_new (gboolean, 1); - (*success_rtn)[0] = (gboolean)success; +} +void viewerappapi_init(ViewerAppAPI *server) +{ + gBusNodeInfo = g_dbus_node_info_new_for_xml (DBUS_SERVER, NULL); + g_assert (gBusNodeInfo != NULL); + + g_bus_own_name(G_BUS_TYPE_SESSION, + VIEWERAPI_SERVICE, + G_BUS_NAME_OWNER_FLAGS_NONE, + busAcquired, + nameAcquired, + nameLost, + NULL, + NULL); - return TRUE; // the invokation succeeded, even if the actual dispatch didn't. } /// @@ -260,13 +242,6 @@ gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **succ //virtual bool LLAppViewerLinux::initSLURLHandler() { - if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME)) - { - return false; // failed - } - - g_type_init(); - //ViewerAppAPI *api_server = (ViewerAppAPI*) g_object_new(viewerappapi_get_type(), NULL); @@ -276,49 +251,49 @@ bool LLAppViewerLinux::initSLURLHandler() //virtual bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url) { - if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME)) + auto *pBus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, nullptr); + + if( !pBus ) { - return false; // failed + LL_WARNS() << "Getting dbus failed." << LL_ENDL; + return false; } - bool success = false; - DBusGConnection *bus; - GError *error = NULL; - - g_type_init(); + auto pProxy = g_dbus_proxy_new_sync(pBus, G_DBUS_PROXY_FLAGS_NONE, nullptr, + VIEWERAPI_SERVICE, VIEWERAPI_PATH, + VIEWERAPI_INTERFACE, nullptr, nullptr); - bus = lldbus_g_bus_get (DBUS_BUS_SESSION, &error); - if (bus) + if( !pProxy ) { - gboolean rtn = FALSE; - DBusGProxy *remote_object = - lldbus_g_proxy_new_for_name(bus, VIEWERAPI_SERVICE, VIEWERAPI_PATH, VIEWERAPI_INTERFACE); - - if (lldbus_g_proxy_call(remote_object, "GoSLURL", &error, - G_TYPE_STRING, url.c_str(), G_TYPE_INVALID, - G_TYPE_BOOLEAN, &rtn, G_TYPE_INVALID)) - { - success = rtn; - } - else - { - LL_INFOS() << "Call-out to other instance failed (perhaps not running): " << error->message << LL_ENDL; - } - - g_object_unref(G_OBJECT(remote_object)); + LL_WARNS() << "Cannot create new dbus proxy." << LL_ENDL; + g_object_unref( pBus ); + return false; } - else + + auto *pArgs = g_variant_new( "(s)", url.c_str() ); + if( !pArgs ) { - LL_WARNS() << "Couldn't connect to session bus: " << error->message << LL_ENDL; + LL_WARNS() << "Cannot create new variant." << LL_ENDL; + g_object_unref( pBus ); + return false; } - if (error) - g_error_free(error); + auto pRes = g_dbus_proxy_call_sync(pProxy, + "GoSLURL", + pArgs, + G_DBUS_CALL_FLAGS_NONE, + -1, nullptr, nullptr); - return success; + + + if( pRes ) + g_variant_unref( pRes ); + g_object_unref( pProxy ); + g_object_unref( pBus ); + return true; } -#else // LL_DBUS_ENABLED +#else // LL_GLIB bool LLAppViewerLinux::initSLURLHandler() { return false; // not implemented without dbus @@ -327,7 +302,7 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url) { return false; // not implemented without dbus } -#endif // LL_DBUS_ENABLED +#endif // LL_GLIB void LLAppViewerLinux::initCrashReporting(bool reportFreeze) { @@ -343,15 +318,18 @@ void LLAppViewerLinux::initCrashReporting(bool reportFreeze) pid_str << LLApp::getPid(); std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); std::string appname = gDirUtilp->getExecutableFilename(); + std::string grid{ LLGridManager::getInstance()->getGridId() }; + std::string title{ LLAppViewer::instance()->getSecondLifeTitle() }; + std::string pidstr{ pid_str.str() }; // launch the actual crash logger const char * cmdargv[] = {cmd.c_str(), "-user", - (char*)LLGridManager::getInstance()->getGridId().c_str(), + grid.c_str(), "-name", - LLAppViewer::instance()->getSecondLifeTitle().c_str(), + title.c_str(), "-pid", - pid_str.str().c_str(), + pidstr.c_str(), "-dumpdir", logdir.c_str(), "-procname", diff --git a/indra/newview/llappviewerlinux.h b/indra/newview/llappviewerlinux.h index dde223878da..460ca721f1f 100644 --- a/indra/newview/llappviewerlinux.h +++ b/indra/newview/llappviewerlinux.h @@ -27,17 +27,6 @@ #ifndef LL_LLAPPVIEWERLINUX_H #define LL_LLAPPVIEWERLINUX_H -extern "C" { -# include -} - -#if LL_DBUS_ENABLED -extern "C" { -# include -# include -} -#endif - #ifndef LL_LLAPPVIEWER_H #include "llappviewer.h" #endif @@ -70,21 +59,4 @@ class LLAppViewerLinux : public LLAppViewer virtual bool sendURLToOtherInstance(const std::string& url); }; -#if LL_DBUS_ENABLED -typedef struct -{ - GObject parent; - DBusGConnection *connection; -} ViewerAppAPI; - -extern "C" { - gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error); -} - -#define VIEWERAPI_SERVICE "com.secondlife.ViewerAppAPIService" -#define VIEWERAPI_PATH "/com/secondlife/ViewerAppAPI" -#define VIEWERAPI_INTERFACE "com.secondlife.ViewerAppAPI" - -#endif // LL_DBUS_ENABLED - #endif // LL_LLAPPVIEWERLINUX_H diff --git a/indra/newview/llappviewerlinux_api.h b/indra/newview/llappviewerlinux_api.h deleted file mode 100644 index 3d1324dd197..00000000000 --- a/indra/newview/llappviewerlinux_api.h +++ /dev/null @@ -1,143 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ -/** - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef __dbus_glib_marshal_viewerapp_MARSHAL_H__ -#define __dbus_glib_marshal_viewerapp_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_char (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* BOOLEAN:STRING,POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.5XXD8T:1) */ -extern void dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer arg_3, - gpointer data2); - register GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER callback; - register GCClosure *cc = (GCClosure*) closure; - register gpointer data1, data2; - gboolean v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 4); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_string (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - g_marshal_value_peek_pointer (param_values + 3), - data2); - - g_value_set_boolean (return_value, v_return); -} - -G_END_DECLS - -#endif /* __dbus_glib_marshal_viewerapp_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_viewerapp_methods[] = { - { (GCallback) viewer_app_api_GoSLURL, dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER, 0 }, -}; - -const DBusGObjectInfo dbus_glib_viewerapp_object_info = { - 0, - dbus_glib_viewerapp_methods, - 1, -"com.secondlife.ViewerAppAPI\0GoSLURL\0S\0slurl\0I\0s\0success_ret\0O\0F\0N\0b\0\0\0", -"\0", -"\0" -}; - diff --git a/indra/newview/llappviewerlinux_api.xml b/indra/newview/llappviewerlinux_api.xml deleted file mode 100644 index fac35b7adc8..00000000000 --- a/indra/newview/llappviewerlinux_api.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/indra/newview/llappviewerlinux_api_dbus.cpp b/indra/newview/llappviewerlinux_api_dbus.cpp deleted file mode 100644 index 9aed8a98d44..00000000000 --- a/indra/newview/llappviewerlinux_api_dbus.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @file llappviewerlinux_api_dbus.cpp - * @brief dynamic DBus symbol-grabbing code - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#if LL_DBUS_ENABLED - -#include "linden_common.h" - -extern "C" { -#include - -#include "apr_pools.h" -#include "apr_dso.h" -} - -#define DEBUGMSG(...) do { LL_DEBUGS() << llformat(__VA_ARGS__) << LL_ENDL; } while(0) -#define INFOMSG(...) do { LL_INFOS() << llformat(__VA_ARGS__) << LL_ENDL; } while(0) -#define WARNMSG(...) do { LL_WARNS() << llformat(__VA_ARGS__) << LL_ENDL; } while(0) - -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) RTN (*ll##DBUSSYM)(__VA_ARGS__) = NULL -#include "llappviewerlinux_api_dbus_syms_raw.inc" -#undef LL_DBUS_SYM - -static bool sSymsGrabbed = false; -static apr_pool_t *sSymDBUSDSOMemoryPool = NULL; -static apr_dso_handle_t *sSymDBUSDSOHandleG = NULL; - -bool grab_dbus_syms(std::string dbus_dso_name) -{ - if (sSymsGrabbed) - { - // already have grabbed good syms - return true; - } - - bool sym_error = false; - bool rtn = false; - apr_status_t rv; - apr_dso_handle_t *sSymDBUSDSOHandle = NULL; - -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##DBUSSYM, sSymDBUSDSOHandle, #DBUSSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #DBUSSYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #DBUSSYM, (void*)ll##DBUSSYM);}while(0) - - //attempt to load the shared library - apr_pool_create(&sSymDBUSDSOMemoryPool, NULL); - - if ( APR_SUCCESS == (rv = apr_dso_load(&sSymDBUSDSOHandle, - dbus_dso_name.c_str(), - sSymDBUSDSOMemoryPool) )) - { - INFOMSG("Found DSO: %s", dbus_dso_name.c_str()); - -#include "llappviewerlinux_api_dbus_syms_raw.inc" - - if ( sSymDBUSDSOHandle ) - { - sSymDBUSDSOHandleG = sSymDBUSDSOHandle; - sSymDBUSDSOHandle = NULL; - } - - rtn = !sym_error; - } - else - { - INFOMSG("Couldn't load DSO: %s", dbus_dso_name.c_str()); - rtn = false; // failure - } - - if (sym_error) - { - WARNMSG("Failed to find necessary symbols in DBUS-GLIB libraries."); - } -#undef LL_DBUS_SYM - - sSymsGrabbed = rtn; - return rtn; -} - - -void ungrab_dbus_syms() -{ - // should be safe to call regardless of whether we've - // actually grabbed syms. - - if ( sSymDBUSDSOHandleG ) - { - apr_dso_unload(sSymDBUSDSOHandleG); - sSymDBUSDSOHandleG = NULL; - } - - if ( sSymDBUSDSOMemoryPool ) - { - apr_pool_destroy(sSymDBUSDSOMemoryPool); - sSymDBUSDSOMemoryPool = NULL; - } - - // NULL-out all of the symbols we'd grabbed -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{ll##DBUSSYM = NULL;}while(0) -#include "llappviewerlinux_api_dbus_syms_raw.inc" -#undef LL_DBUS_SYM - - sSymsGrabbed = false; -} - -#endif // LL_DBUS_ENABLED diff --git a/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc b/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc deleted file mode 100644 index c0548e2fba2..00000000000 --- a/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc +++ /dev/null @@ -1,9 +0,0 @@ - -// required symbols to grab -LL_DBUS_SYM(true, dbus_g_bus_get, DBusGConnection*, DBusBusType, GError**); -LL_DBUS_SYM(true, dbus_g_proxy_new_for_name, DBusGProxy*, DBusGConnection*, const char *, const char*, const char*); -LL_DBUS_SYM(true, dbus_g_proxy_call, gboolean, DBusGProxy*, const char*, GError**, GType, ...); -LL_DBUS_SYM(true, dbus_g_object_type_install_info, void, GType, const DBusGObjectInfo*); -LL_DBUS_SYM(true, dbus_g_connection_register_g_object, void, DBusGConnection*, const char*, GObject*); - -// optional symbols to grab diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index e967ff3df29..2dba778e245 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -37,6 +37,10 @@ #include "llviewercontrol.h" #include "llwin32headers.h" +#if LL_SDL_WINDOW +#include "SDL3/SDL.h" +#endif + #if LL_LINUX || LL_DARWIN # include "llfilepicker.h" #endif @@ -65,7 +69,103 @@ bool LLDirPicker::check_local_file_access_enabled() return true; } -#if LL_WINDOWS +#if LL_SDL_WINDOW + +LLDirPicker::LLDirPicker() : + mFileName(NULL), + mLocked(false) +{ + reset(); +} + +LLDirPicker::~LLDirPicker() +{ +} + +void LLDirPicker::reset() +{ +} + +bool LLDirPicker::getDir(std::string* filename, bool blocking) +{ + return false; +} + +std::string LLDirPicker::getDirName() +{ + return {}; +} + +bool LLDirPicker::getDirModeless(std::string* filename, + void (*callback)(bool, std::string&, void*), + void* userdata) +{ + if (mLocked) + { + return false; + } + + // if local file browsing is turned off, return without opening dialog + if (!check_local_file_access_enabled()) + { + return false; + } + + { + struct LLSDLFileUserdata + { + LLSDLFileUserdata(void (*callback_func)(bool, std::string&, void*), void* callback_userdata) + : mCallback(callback_func), mUserdata(callback_userdata) + { + } + void (*mCallback)(bool, std::string&, void*); + void* mUserdata; + }; + + auto sdl_callback = [](void* userdata, const char* const* filelist, int filter) + { + LLSDLFileUserdata* callback_struct = (LLSDLFileUserdata*)userdata; + + auto* callback_func = callback_struct->mCallback; + auto* callback_data = callback_struct->mUserdata; + delete callback_struct; // delete callback container + + std::string rtn; + if (!filelist) + { + LL_WARNS() << "Error during SDL folder picking: " << SDL_GetError() << LL_ENDL; + callback_func(false, rtn, callback_data); + return; + } + else if (!*filelist) + { + LL_INFOS() << "User did not select any folders. Dialog likely cancelled." << LL_ENDL; + callback_func(false, rtn, callback_data); + return; + } + + while (*filelist) { + rtn = std::string(*filelist); + break; + } + callback_func(true, rtn, callback_data); + + }; + + LLSDLFileUserdata* llfilecallback = new LLSDLFileUserdata(callback, userdata); + + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, SDL_GL_GetCurrentWindow()); + SDL_ShowFileDialogWithProperties(SDL_FILEDIALOG_OPENFOLDER, sdl_callback, llfilecallback, props); + + SDL_DestroyProperties(props); + } + + return true; +} + + +#elif LL_WINDOWS LLDirPicker::LLDirPicker() : mFileName(NULL), @@ -167,6 +267,13 @@ bool LLDirPicker::getDir(std::string* filename, bool blocking) return success; } +bool LLDirPicker::getDirModeless(std::string* filename, + void (*callback)(bool, std::string&, void*), + void* userdata) +{ + return false; +} + std::string LLDirPicker::getDirName() { return mDir; @@ -195,7 +302,6 @@ void LLDirPicker::reset() } -//static bool LLDirPicker::getDir(std::string* filename, bool blocking) { LLFilePicker::ELoadFilter filter=LLFilePicker::FFLOAD_DIRECTORY; @@ -203,6 +309,13 @@ bool LLDirPicker::getDir(std::string* filename, bool blocking) return mFilePicker->getOpenFile(filter, true); } +bool LLDirPicker::getDirModeless(std::string* filename, + void (*callback)(bool, std::string&, void*), + void* userdata) +{ + return false; +} + std::string LLDirPicker::getDirName() { return mFilePicker->getFirstFile(); @@ -240,23 +353,13 @@ bool LLDirPicker::getDir(std::string* filename, bool blocking) return false; } -#if !LL_MESA_HEADLESS - - if (mFilePicker) - { - GtkWindow* picker = mFilePicker->buildFilePicker(false, true, - "dirpicker"); - - if (picker) - { - gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("choose_the_directory").c_str()); - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - return (!mFilePicker->getFirstFile().empty()); - } - } -#endif // !LL_MESA_HEADLESS + return false; +} +bool LLDirPicker::getDirModeless(std::string* filename, + void (*callback)(bool, std::string&, void*), + void* userdata) +{ return false; } @@ -290,6 +393,13 @@ bool LLDirPicker::getDir(std::string* filename, bool blocking) return false; } +bool LLDirPicker::getDirModeless(std::string* filename, + void (*callback)(bool, std::string&, void*), + void* userdata) +{ + return false; +} + std::string LLDirPicker::getDirName() { return ""; @@ -303,7 +413,9 @@ std::queue LLDirPickerThread::sDeadQ; void LLDirPickerThread::getFile() { -#if LL_WINDOWS +#if LL_SDL_WINDOW + runModeless(); +#elif LL_WINDOWS start(); #else run(); @@ -333,6 +445,32 @@ void LLDirPickerThread::run() } +void LLDirPickerThread::runModeless() +{ + LLDirPicker picker; + bool result = picker.getDirModeless(&mProposedName, modelessStringCallback, this); + if (!result) + { + LLMutexLock lock(sMutex); + sDeadQ.push(this); + } +} + +void LLDirPickerThread::modelessStringCallback(bool success, + std::string& response, + void* user_data) +{ + LLDirPickerThread* picker = (LLDirPickerThread*)user_data; + { + LLMutexLock lock(sMutex); + if (success) + { + picker->mResponses.push_back(response); + } + sDeadQ.push(picker); + } +} + //static void LLDirPickerThread::initClass() { diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h index dc740caab27..c3619f91f54 100644 --- a/indra/newview/lldirpicker.h +++ b/indra/newview/lldirpicker.h @@ -58,6 +58,9 @@ class LLDirPicker { public: bool getDir(std::string* filename, bool blocking = true); + bool getDirModeless(std::string* filename, + void (*callback)(bool, std::string&, void*), + void* userdata); std::string getDirName(); // clear any lists of buffers or whatever, and make sure the dir @@ -116,6 +119,11 @@ class LLDirPickerThread : public LLThread virtual void run(); + void runModeless(); + static void modelessStringCallback(bool success, + std::string& response, + void* user_data); + virtual void notify(const std::vector& filenames); private: diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 0e754c95612..62500a10e0d 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -36,7 +36,7 @@ #include "llviewercontrol.h" #include "llwindow.h" // beforeDialog() -#if LL_SDL +#if LL_SDL_WINDOW #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers #endif // LL_SDL @@ -50,7 +50,7 @@ LLFilePicker LLFilePicker::sInstance; -#if LL_WINDOWS +#if LL_WINDOWS && !LL_SDL_WINDOW #define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0" #define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0" #define ANIM_FILTER L"Animations (*.bvh; *.anim)\0*.bvh;*.anim\0" @@ -82,7 +82,7 @@ LLFilePicker::LLFilePicker() { reset(); -#if LL_WINDOWS +#if LL_WINDOWS && !LL_SDL_WINDOW mOFN.lStructSize = sizeof(OPENFILENAMEW); mOFN.hwndOwner = NULL; // Set later mOFN.hInstance = NULL; @@ -102,7 +102,7 @@ LLFilePicker::LLFilePicker() mOFN.lpfnHook = NULL; mOFN.lpTemplateName = NULL; mFilesW[0] = '\0'; -#elif LL_DARWIN +#elif LL_DARWIN && !LL_SDL_WINDOW mPickOptions = 0; #endif @@ -167,7 +167,449 @@ void LLFilePicker::reset() mCurrentFile = 0; } -#if LL_WINDOWS +#if LL_SDL_WINDOW + +namespace +{ + std::vector setupLoadFilter(LLFilePicker::ELoadFilter filter) + { + std::vector filter_vec; + + switch (filter) + { + case LLFilePicker::FFLOAD_ALL: + case LLFilePicker::FFLOAD_EXE: + filter_vec.push_back({ "All Files (*.*)", "*" }); + filter_vec.push_back({ "Sounds (*.wav)", "wav" }); + filter_vec.push_back({ "Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)", "tga;bmp;jpg;jpeg;png" }); + filter_vec.push_back({ "Animations (*.bvh; *.anim)", "bvh;anim" }); + filter_vec.push_back({ "GLTF Files (*.gltf; *.glb)", "gltf;glb" }); + break; + case LLFilePicker::FFLOAD_WAV: + filter_vec.push_back({ "Sounds (*.wav)", "wav" }); + break; + case LLFilePicker::FFLOAD_IMAGE: + filter_vec.push_back({ "Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)", "tga;bmp;jpg;jpeg;png" }); + break; + case LLFilePicker::FFLOAD_ANIM: + filter_vec.push_back({ "Animations (*.bvh; *.anim)", "bvh;anim" }); + break; + case LLFilePicker::FFLOAD_GLTF: + filter_vec.push_back({ "glTF (*.gltf; *.glb)", "gltf;glb" }); + break; + case LLFilePicker::FFLOAD_COLLADA: + filter_vec.push_back({ "Scene (*.dae)", "dae" }); + break; + case LLFilePicker::FFLOAD_XML: + filter_vec.push_back({ "XML files (*.xml)", "xml" }); + break; + case LLFilePicker::FFLOAD_SLOBJECT: + filter_vec.push_back({ "Objects (*.slobject)", "slobject" }); + break; + case LLFilePicker::FFLOAD_RAW: + filter_vec.push_back({ "RAW files (*.raw)", "raw" }); + break; + case LLFilePicker::FFLOAD_MODEL: + filter_vec.push_back({ "Model files (*.dae)", "dae" }); + break; + case LLFilePicker::FFLOAD_MATERIAL: + filter_vec.push_back({ "GLTF Files (*.gltf; *.glb)", "gltf;glb" }); + break; + case LLFilePicker::FFLOAD_MATERIAL_TEXTURE: + filter_vec.push_back({ "GLTF Import (*.gltf; *.glb; *.tga; *.bmp; *.jpg; *.jpeg; *.png)", "gltf;glb;tga;bmp;jpg;jpeg;png" }); + filter_vec.push_back({ "GLTF Files (*.gltf; *.glb)", "gltf;glb" }); + filter_vec.push_back({ "Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)", "tga;bmp;jpg;jpeg;png" }); + break; + case LLFilePicker::FFLOAD_HDRI: + filter_vec.push_back({ "HDRI Files (*.exr)", "exr" }); + break; + case LLFilePicker::FFLOAD_SCRIPT: + filter_vec.push_back({ "Script files (*.lsl)", "lsl" }); + break; + case LLFilePicker::FFLOAD_DICTIONARY: + filter_vec.push_back({ "Dictionary files (*.dic; *.xcu)", "dic;xcu" }); + break; + default: + break; + } + return filter_vec; + } +} + +bool LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) +{ + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return false; +} + +bool LLFilePicker::getOpenFileModeless(ELoadFilter filter, + void (*callback)(bool, std::vector&, void*), + void* userdata) +{ + if (mLocked) + { + return false; + } + + // if local file browsing is turned off, return without opening dialog + if (!check_local_file_access_enabled()) + { + return false; + } + + auto file_filters = setupLoadFilter(filter); + + reset(); + + { + struct LLSDLFileUserdata + { + LLSDLFileUserdata(void (*callback_func)(bool, std::vector&, void*), void* callback_userdata) + : mCallback(callback_func), mUserdata(callback_userdata) + { + } + void (*mCallback)(bool, std::vector&, void*); + void* mUserdata; + }; + + auto sdl_callback = [](void* userdata, const char* const* filelist, int filter) + { + LLSDLFileUserdata* callback_struct = (LLSDLFileUserdata*)userdata; + + auto* callback_func = callback_struct->mCallback; + auto* callback_data = callback_struct->mUserdata; + delete callback_struct; // delete callback container + + std::vector rtn; + + if (!filelist) + { + LL_WARNS() << "Error during SDL file picking: " << SDL_GetError() << LL_ENDL; + callback_func(false, rtn, callback_data); + return; + } + else if (!*filelist) + { + LL_INFOS() << "User did not select any file. Dialog likely cancelled." << LL_ENDL; + callback_func(false, rtn, callback_data); + return; + } + + while (*filelist) + { + rtn.push_back(std::string(*filelist)); + filelist++; + } + + callback_func(true, rtn, callback_data); + + }; + + LLSDLFileUserdata* llfilecallback = new LLSDLFileUserdata(callback, userdata); + + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, file_filters.data()); + SDL_SetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, file_filters.size()); + SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, SDL_GL_GetCurrentWindow()); + SDL_SetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false); + + SDL_ShowFileDialogWithProperties(SDL_FILEDIALOG_OPENFILE, sdl_callback, llfilecallback, props); + + SDL_DestroyProperties(props); + } + return true; +} + +bool LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) +{ + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return false; +} + +bool LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, + void (*callback)(bool, std::vector&, void*), + void* userdata) +{ + if (mLocked) + { + return false; + } + + // if local file browsing is turned off, return without opening dialog + if (!check_local_file_access_enabled()) + { + return false; + } + + auto file_filters = setupLoadFilter(filter); + + reset(); + + { + struct LLSDLFileUserdata + { + LLSDLFileUserdata(void (*callback_func)(bool, std::vector&, void*), void* callback_userdata) + : mCallback(callback_func), mUserdata(callback_userdata) + { + } + void (*mCallback)(bool, std::vector&, void*); + void* mUserdata; + }; + + auto sdl_callback = [](void* userdata, const char* const* filelist, int filter) + { + LLSDLFileUserdata* callback_struct = (LLSDLFileUserdata*)userdata; + + auto* callback_func = callback_struct->mCallback; + auto* callback_data = callback_struct->mUserdata; + delete callback_struct; // delete callback container + + std::vector rtn; + + if (!filelist) + { + LL_WARNS() << "Error during SDL file picking: " << SDL_GetError() << LL_ENDL; + callback_func(false, rtn, callback_data); + return; + } + else if (!*filelist) + { + LL_INFOS() << "User did not select any file. Dialog likely cancelled." << LL_ENDL; + callback_func(false, rtn, callback_data); + return; + } + + while (*filelist) + { + rtn.push_back(std::string(*filelist)); + filelist++; + } + + callback_func(true, rtn, callback_data); + + }; + + LLSDLFileUserdata* llfilecallback = new LLSDLFileUserdata(callback, userdata); + + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, file_filters.data()); + SDL_SetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, file_filters.size()); + SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, SDL_GL_GetCurrentWindow()); + SDL_SetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, true); + + SDL_ShowFileDialogWithProperties(SDL_FILEDIALOG_OPENFILE, sdl_callback, llfilecallback, props); + + SDL_DestroyProperties(props); + } + + return true; +} + +bool LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, bool blocking) +{ + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return false; +} + +bool LLFilePicker::getSaveFileModeless(ESaveFilter filter, + const std::string& filename, + void (*callback)(bool, std::string&, void*), + void* userdata) +{ + if (mLocked) + { + return false; + } + + // if local file browsing is turned off, return without opening dialog + if (!check_local_file_access_enabled()) + { + return false; + } + + std::string default_filename; + if (!filename.empty()) + { + default_filename = filename; + } + + std::vector file_filters; + + switch (filter) + { + case FFSAVE_ALL: + file_filters.push_back({ "All Files (*.*)", "*" }); + file_filters.push_back({ "WAV Sounds (*.wav)", "wav" }); + file_filters.push_back({ "Targa, Bitmap Images (*.tga; *.bmp)", "tga;bmp" }); + break; + case FFSAVE_WAV: + if (default_filename.empty()) + { + default_filename = "untitled.wav"; + } + file_filters.push_back({ "WAV Sounds (*.wav)", "wav" }); + break; + case FFSAVE_TGA: + if (default_filename.empty()) + { + default_filename = "untitled.tga"; + } + file_filters.push_back({ "Targa Images (*.tga)", "tga" }); + break; + case FFSAVE_BMP: + if (default_filename.empty()) + { + default_filename = "untitled.bmp"; + } + file_filters.push_back({ "Bitmap Images (*.bmp)", "bmp" }); + break; + case FFSAVE_PNG: + if (default_filename.empty()) + { + default_filename = "untitled.png"; + } + file_filters.push_back({ "PNG Images (*.png)", "png" }); + break; + case FFSAVE_TGAPNG: + if (default_filename.empty()) + { + //PNG by default + default_filename = "untitled.png"; + } + file_filters.push_back({ "PNG Images (*.png)", "png" }); + file_filters.push_back({ "Targa Images (*.tga)", "tga" }); + break; + + case FFSAVE_JPEG: + if (default_filename.empty()) + { + default_filename = "untitled.jpeg"; + } + file_filters.push_back({ "JPEG Images (*.jpg *.jpeg)", "jpg;jpeg" }); + break; + case FFSAVE_AVI: + if (default_filename.empty()) + { + default_filename = "untitled.avi"; + } + file_filters.push_back({ "AVI Movie File (*.avi)", "avi" }); + break; + case FFSAVE_ANIM: + if (default_filename.empty()) + { + default_filename = "untitled.xaf"; + } + file_filters.push_back({ "XAF Anim File (*.xaf)", "xaf" }); + break; + case FFSAVE_GLTF: + if (default_filename.empty()) + { + default_filename = "untitled.gltf"; + } + file_filters.push_back({ "glTF Asset File (*.gltf)", "gltf" }); + break; + case FFSAVE_XML: + if (default_filename.empty()) + { + default_filename = "untitled.xml"; + } + file_filters.push_back({ "XML File (*.xml)", "xml" }); + break; + case FFSAVE_COLLADA: + if (default_filename.empty()) + { + default_filename = "untitled.collada"; + } + file_filters.push_back({ "COLLADA File (*.collada)", "collada" }); + break; + case FFSAVE_RAW: + if (default_filename.empty()) + { + default_filename = "untitled.raw"; + } + file_filters.push_back({ "RAW files (*.raw)", "raw" }); + break; + case FFSAVE_J2C: + if (default_filename.empty()) + { + default_filename = "untitled.j2c"; + } + file_filters.push_back({ "Compressed Images (*.j2c)", "j2c" }); + break; + case FFSAVE_SCRIPT: + if (default_filename.empty()) + { + default_filename = "untitled.lsl"; + } + file_filters.push_back({ "LSL Files (*.lsl)", "lsl" }); + break; + default: + return false; + } + + reset(); + + { + struct LLSDLFileUserdata + { + LLSDLFileUserdata(void (*callback_func)(bool, std::string&, void*), void* callback_userdata) + : mCallback(callback_func), mUserdata(callback_userdata) + { + } + void (*mCallback)(bool, std::string&, void*); + void* mUserdata; + }; + + auto sdl_callback = [](void* userdata, const char* const* filelist, int filter) + { + LLSDLFileUserdata* callback_struct = (LLSDLFileUserdata*)userdata; + + auto* callback_func = callback_struct->mCallback; + auto* callback_data = callback_struct->mUserdata; + delete callback_struct; // delete callback container + + std::string rtn; + if (!filelist) + { + LL_WARNS() << "Error during SDL file picking: " << SDL_GetError() << LL_ENDL; + callback_func(false, rtn, callback_data); + return; + } + else if (!*filelist) + { + LL_INFOS() << "User did not select any file. Dialog likely cancelled." << LL_ENDL; + callback_func(false, rtn, callback_data); + return; + } + + while (*filelist) { + rtn = std::string(*filelist); + break; + } + callback_func(true, rtn, callback_data); + + }; + + LLSDLFileUserdata* llfilecallback = new LLSDLFileUserdata(callback, userdata); + + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, file_filters.data()); + SDL_SetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, file_filters.size()); + SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, SDL_GL_GetCurrentWindow()); + if(!default_filename.empty()) + { + SDL_SetStringProperty(props, SDL_PROP_FILE_DIALOG_LOCATION_STRING, default_filename.c_str()); + } + SDL_SetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false); + + SDL_ShowFileDialogWithProperties(SDL_FILEDIALOG_SAVEFILE, sdl_callback, llfilecallback, props); + + SDL_DestroyProperties(props); + } + + return true; +} +#elif LL_WINDOWS bool LLFilePicker::setupFilter(ELoadFilter filter) { @@ -1107,488 +1549,6 @@ bool LLFilePicker::getSaveFileModeless(ESaveFilter filter, #elif LL_LINUX -# if LL_GTK - -// static -void LLFilePicker::add_to_selectedfiles(gpointer data, gpointer user_data) -{ - // We need to run g_filename_to_utf8 in the user's locale - std::string saved_locale(setlocale(LC_ALL, NULL)); - setlocale(LC_ALL, ""); - - LLFilePicker* picker = (LLFilePicker*) user_data; - GError *error = NULL; - gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, - -1, NULL, NULL, &error); - if (error) - { - // *FIXME. - // This condition should really be notified to the user, e.g. - // through a message box. Just logging it is inappropriate. - - // g_filename_display_name is ideal, but >= glib 2.6, so: - // a hand-rolled hacky makeASCII which disallows control chars - std::string display_name; - for (const gchar *str = (const gchar *)data; *str; str++) - { - display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?'); - } - LL_WARNS() << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << LL_ENDL; - } - - if (filename_utf8) - { - picker->mFiles.push_back(std::string(filename_utf8)); - LL_DEBUGS() << "ADDED FILE " << filename_utf8 << LL_ENDL; - g_free(filename_utf8); - } - - setlocale(LC_ALL, saved_locale.c_str()); -} - -// static -void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer user_data) -{ - LLFilePicker* picker = (LLFilePicker*)user_data; - - LL_DEBUGS() << "GTK DIALOG RESPONSE " << response << LL_ENDL; - - if (response == GTK_RESPONSE_ACCEPT) - { - GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); - g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); - g_slist_foreach(file_list, (GFunc)g_free, NULL); - g_slist_free (file_list); - } - - // let's save the extension of the last added file(considering current filter) - GtkFileFilter *gfilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widget)); - if(gfilter) - { - std::string filter = gtk_file_filter_get_name(gfilter); - - if(filter == LLTrans::getString("png_image_files")) - { - picker->mCurrentExtension = ".png"; - } - else if(filter == LLTrans::getString("targa_image_files")) - { - picker->mCurrentExtension = ".tga"; - } - } - - // set the default path for this usage context. - const char* cur_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget)); - if (cur_folder != NULL) - { - picker->mContextToPathMap[picker->mCurContextName] = cur_folder; - } - - gtk_widget_destroy(widget); - gtk_main_quit(); -} - - -GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::string context) -{ -#ifndef LL_MESA_HEADLESS - if (LLWindowSDL::ll_try_gtk_init()) - { - GtkWidget *win = NULL; - GtkFileChooserAction pickertype = - is_save? - (is_folder? - GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : - GTK_FILE_CHOOSER_ACTION_SAVE) : - (is_folder? - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : - GTK_FILE_CHOOSER_ACTION_OPEN); - - win = gtk_file_chooser_dialog_new(NULL, NULL, - pickertype, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - is_folder ? - GTK_STOCK_APPLY : - (is_save ? - GTK_STOCK_SAVE : - GTK_STOCK_OPEN), - GTK_RESPONSE_ACCEPT, - (gchar *)NULL); - mCurContextName = context; - - // get the default path for this usage context if it's been - // seen before. - std::map::iterator - this_path = mContextToPathMap.find(context); - if (this_path != mContextToPathMap.end()) - { - gtk_file_chooser_set_current_folder - (GTK_FILE_CHOOSER(win), - this_path->second.c_str()); - } - -# if LL_X11 - // Make GTK tell the window manager to associate this - // dialog with our non-GTK raw X11 window, which should try - // to keep it on top etc. - Window XWindowID = LLWindowSDL::get_SDL_XWindowID(); - if (None != XWindowID) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } - else - { - LL_WARNS() << "Hmm, couldn't get xwid to use for transient." << LL_ENDL; - } -# endif //LL_X11 - - g_signal_connect (GTK_FILE_CHOOSER(win), - "response", - G_CALLBACK(LLFilePicker::chooser_responder), - this); - - gtk_window_set_modal(GTK_WINDOW(win), TRUE); - - /* GTK 2.6: if (is_folder) - gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), - TRUE); */ - - return GTK_WINDOW(win); - } - else - { - return NULL; - } -#else - return NULL; -#endif //LL_MESA_HEADLESS -} - -static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter, - GtkWindow *picker, - std::string filtername) -{ - gtk_file_filter_set_name(gfilter, filtername.c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter); - GtkFileFilter *allfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(allfilter, "*"); - gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); - gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); -} - -static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker, - std::string pattern, - std::string filtername) -{ - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, pattern.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; -} - -static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker, - std::string mime, - std::string filtername) -{ - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_mime_type(gfilter, mime.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; -} - -static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker) -{ - return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav", - LLTrans::getString("sound_files") + " (*.wav)"); -} - -static std::string add_anim_filter_to_gtkchooser(GtkWindow *picker) -{ - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.bvh"); - gtk_file_filter_add_pattern(gfilter, "*.anim"); - std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; -} - -static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker) -{ - return add_simple_pattern_filter_to_gtkchooser(picker, "*.xml", - LLTrans::getString("xml_files") + " (*.xml)"); -} - -static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker) -{ - return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae", - LLTrans::getString("scene_files") + " (*.dae)"); -} - -static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) -{ - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.tga"); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str()); - std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; -} - -static std::string add_script_filter_to_gtkchooser(GtkWindow *picker) -{ - return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, - LLTrans::getString("script_files") + " (*.lsl)"); -} - -static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker) -{ - return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, - LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); -} - -static std::string add_save_texture_filter_to_gtkchooser(GtkWindow *picker) -{ - GtkFileFilter *gfilter_tga = gtk_file_filter_new(); - GtkFileFilter *gfilter_png = gtk_file_filter_new(); - - gtk_file_filter_add_pattern(gfilter_tga, "*.tga"); - gtk_file_filter_add_mime_type(gfilter_png, "image/png"); - std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)"; - gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str()); - gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str()); - - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter_png); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter_tga); - return caption; -} - -bool LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking ) -{ - bool rtn = false; - - // if local file browsing is turned off, return without opening dialog - if (!check_local_file_access_enabled()) - { - return false; - } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(true, false, "savefile"); - - if (picker) - { - std::string suggest_name = "untitled"; - std::string suggest_ext = ""; - std::string caption = LLTrans::getString("save_file_verb") + " "; - switch (filter) - { - case FFSAVE_WAV: - caption += add_wav_filter_to_gtkchooser(picker); - suggest_ext = ".wav"; - break; - case FFSAVE_TGA: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); - suggest_ext = ".tga"; - break; - case FFSAVE_BMP: - caption += add_simple_mime_filter_to_gtkchooser - (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)"); - suggest_ext = ".bmp"; - break; - case FFSAVE_PNG: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)"); - suggest_ext = ".png"; - break; - case FFSAVE_TGAPNG: - caption += add_save_texture_filter_to_gtkchooser(picker); - suggest_ext = ".png"; - break; - case FFSAVE_AVI: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "video/x-msvideo", - LLTrans::getString("avi_movie_file") + " (*.avi)"); - suggest_ext = ".avi"; - break; - case FFSAVE_ANIM: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); - suggest_ext = ".xaf"; - break; - case FFSAVE_XML: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); - suggest_ext = ".xml"; - break; - case FFSAVE_RAW: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); - suggest_ext = ".raw"; - break; - case FFSAVE_J2C: - // *TODO: Should this be 'image/j2c' ? - caption += add_simple_mime_filter_to_gtkchooser - (picker, "images/jp2", - LLTrans::getString("compressed_image_files") + " (*.j2c)"); - suggest_ext = ".j2c"; - break; - case FFSAVE_SCRIPT: - caption += add_script_filter_to_gtkchooser(picker); - suggest_ext = ".lsl"; - break; - default:; - break; - } - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - if (filename.empty()) - { - suggest_name += suggest_ext; - - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), - suggest_name.c_str()); - } - else - { - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), filename.c_str()); - } - - gtk_widget_show_all(GTK_WIDGET(picker)); - - gtk_main(); - - rtn = (getFileCount() == 1); - - if(rtn && filter == FFSAVE_TGAPNG) - { - std::string selected_file = mFiles.back(); - mFiles.pop_back(); - mFiles.push_back(selected_file + mCurrentExtension); - } - } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; -} - -bool LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) -{ - bool rtn = false; - - // if local file browsing is turned off, return without opening dialog - if (!check_local_file_access_enabled()) - { - return false; - } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); - - if (picker) - { - std::string caption = LLTrans::getString("load_file_verb") + " "; - std::string filtername = ""; - switch (filter) - { - case FFLOAD_WAV: - filtername = add_wav_filter_to_gtkchooser(picker); - break; - case FFLOAD_ANIM: - filtername = add_anim_filter_to_gtkchooser(picker); - break; - case FFLOAD_XML: - filtername = add_xml_filter_to_gtkchooser(picker); - break; - case FFLOAD_GLTF: - filtername = dead_code_should_blow_up_here(picker); - break; - case FFLOAD_COLLADA: - filtername = add_collada_filter_to_gtkchooser(picker); - break; - case FFLOAD_IMAGE: - filtername = add_imageload_filter_to_gtkchooser(picker); - break; - case FFLOAD_SCRIPT: - filtername = add_script_filter_to_gtkchooser(picker); - break; - case FFLOAD_DICTIONARY: - filtername = add_dictionary_filter_to_gtkchooser(picker); - break; - default:; - break; - } - - caption += filtername; - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - - rtn = (getFileCount() == 1); - } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; -} - -bool LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) -{ - bool rtn = false; - - // if local file browsing is turned off, return without opening dialog - if (!check_local_file_access_enabled()) - { - return false; - } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); - - if (picker) - { - gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), - TRUE); - - gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); - - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - rtn = !mFiles.empty(); - } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; -} - -# else // LL_GTK - // Hacky stubs designed to facilitate fake getSaveFile and getOpenFile with // static results, when we don't have a real filepicker. @@ -1676,8 +1636,6 @@ bool LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, return false; } -#endif // LL_GTK - #else // not implemented bool LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename ) diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 75ff14f4cfd..5a4da61ccaa 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -35,6 +35,8 @@ #include "stdtypes.h" +#include + #if LL_DARWIN #include @@ -43,7 +45,6 @@ #undef check #undef require -#include #include "llstring.h" #endif @@ -54,19 +55,8 @@ #include #endif -extern "C" { -// mostly for Linux, possible on others -#if LL_GTK -# include "gtk/gtk.h" -#endif // LL_GTK -} - class LLFilePicker { -#ifdef LL_GTK - friend class LLDirPicker; - friend void chooser_responder(GtkWidget *, gint, gpointer); -#endif // LL_GTK public: // calling this before main() is undefined static LLFilePicker& instance( void ) { return sInstance; } @@ -161,14 +151,14 @@ class LLFilePicker // is enabled and if not, tidy up and indicate we're not allowed to do this. bool check_local_file_access_enabled(); -#if LL_WINDOWS +#if LL_WINDOWS && !LL_SDL_WINDOW OPENFILENAMEW mOFN; // for open and save dialogs WCHAR mFilesW[FILENAME_BUFFER_SIZE]; bool setupFilter(ELoadFilter filter); #endif -#if LL_DARWIN +#if LL_DARWIN && !LL_SDL_WINDOW S32 mPickOptions; std::vector mFileVector; @@ -184,28 +174,12 @@ class LLFilePicker void *userdata); #endif -#if LL_GTK - static void add_to_selectedfiles(gpointer data, gpointer user_data); - static void chooser_responder(GtkWidget *widget, gint response, gpointer user_data); - // we remember the last path that was accessed for a particular usage - std::map mContextToPathMap; - std::string mCurContextName; - // we also remember the extension of the last added file. - std::string mCurrentExtension; -#endif - std::vector mFiles; S32 mCurrentFile; bool mLocked; static LLFilePicker sInstance; -protected: -#if LL_GTK - GtkWindow* buildFilePicker(bool is_save, bool is_folder, - std::string context = "generic"); -#endif - public: // don't call these directly please. LLFilePicker(); diff --git a/indra/newview/llfloaterpostprocess.cpp b/indra/newview/llfloaterpostprocess.cpp deleted file mode 100644 index 616c13cdc79..00000000000 --- a/indra/newview/llfloaterpostprocess.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/** - * @file llfloaterpostprocess.cpp - * @brief LLFloaterPostProcess class definition - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloaterpostprocess.h" - -#include "llsliderctrl.h" -#include "llcheckboxctrl.h" -#include "llnotificationsutil.h" -#include "lluictrlfactory.h" -#include "llviewerdisplay.h" -#include "llpostprocess.h" -#include "llcombobox.h" -#include "lllineeditor.h" -#include "llviewerwindow.h" - - -LLFloaterPostProcess::LLFloaterPostProcess(const LLSD& key) - : LLFloater(key) -{ -} - -LLFloaterPostProcess::~LLFloaterPostProcess() -{ - - -} -bool LLFloaterPostProcess::postBuild() -{ - /// Color Filter Callbacks - childSetCommitCallback("ColorFilterToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_color_filter"); - //childSetCommitCallback("ColorFilterGamma", &LLFloaterPostProcess::onFloatControlMoved, &(gPostProcess->tweaks.gamma())); - childSetCommitCallback("ColorFilterBrightness", &LLFloaterPostProcess::onFloatControlMoved, (char*)"brightness"); - childSetCommitCallback("ColorFilterSaturation", &LLFloaterPostProcess::onFloatControlMoved, (char*)"saturation"); - childSetCommitCallback("ColorFilterContrast", &LLFloaterPostProcess::onFloatControlMoved, (char*)"contrast"); - - childSetCommitCallback("ColorFilterBaseR", &LLFloaterPostProcess::onColorControlRMoved, (char*)"contrast_base"); - childSetCommitCallback("ColorFilterBaseG", &LLFloaterPostProcess::onColorControlGMoved, (char*)"contrast_base"); - childSetCommitCallback("ColorFilterBaseB", &LLFloaterPostProcess::onColorControlBMoved, (char*)"contrast_base"); - childSetCommitCallback("ColorFilterBaseI", &LLFloaterPostProcess::onColorControlIMoved, (char*)"contrast_base"); - - /// Night Vision Callbacks - childSetCommitCallback("NightVisionToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_night_vision"); - childSetCommitCallback("NightVisionBrightMult", &LLFloaterPostProcess::onFloatControlMoved, (char*)"brightness_multiplier"); - childSetCommitCallback("NightVisionNoiseSize", &LLFloaterPostProcess::onFloatControlMoved, (char*)"noise_size"); - childSetCommitCallback("NightVisionNoiseStrength", &LLFloaterPostProcess::onFloatControlMoved, (char*)"noise_strength"); - - /// Bloom Callbacks - childSetCommitCallback("BloomToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_bloom"); - childSetCommitCallback("BloomExtract", &LLFloaterPostProcess::onFloatControlMoved, (char*)"extract_low"); - childSetCommitCallback("BloomSize", &LLFloaterPostProcess::onFloatControlMoved, (char*)"bloom_width"); - childSetCommitCallback("BloomStrength", &LLFloaterPostProcess::onFloatControlMoved, (char*)"bloom_strength"); - - // Effect loading and saving. - LLComboBox* comboBox = getChild("PPEffectsCombo"); - getChild("PPLoadEffect")->setCommitCallback(boost::bind(&LLFloaterPostProcess::onLoadEffect, this, comboBox)); - comboBox->setCommitCallback(boost::bind(&LLFloaterPostProcess::onChangeEffectName, this, _1)); - - LLLineEditor* editBox = getChild("PPEffectNameEditor"); - getChild("PPSaveEffect")->setCommitCallback(boost::bind(&LLFloaterPostProcess::onSaveEffect, this, editBox)); - - syncMenu(); - return true; -} - -// Bool Toggle -void LLFloaterPostProcess::onBoolToggle(LLUICtrl* ctrl, void* userData) -{ - char const * boolVariableName = (char const *)userData; - - // check the bool - LLCheckBoxCtrl* cbCtrl = static_cast(ctrl); - gPostProcess->tweaks[boolVariableName] = cbCtrl->getValue(); -} - -// Float Moved -void LLFloaterPostProcess::onFloatControlMoved(LLUICtrl* ctrl, void* userData) -{ - char const * floatVariableName = (char const *)userData; - LLSliderCtrl* sldrCtrl = static_cast(ctrl); - gPostProcess->tweaks[floatVariableName] = sldrCtrl->getValue(); -} - -// Color Moved -void LLFloaterPostProcess::onColorControlRMoved(LLUICtrl* ctrl, void* userData) -{ - char const * floatVariableName = (char const *)userData; - LLSliderCtrl* sldrCtrl = static_cast(ctrl); - gPostProcess->tweaks[floatVariableName][0] = sldrCtrl->getValue(); -} - -// Color Moved -void LLFloaterPostProcess::onColorControlGMoved(LLUICtrl* ctrl, void* userData) -{ - char const * floatVariableName = (char const *)userData; - LLSliderCtrl* sldrCtrl = static_cast(ctrl); - gPostProcess->tweaks[floatVariableName][1] = sldrCtrl->getValue(); -} - -// Color Moved -void LLFloaterPostProcess::onColorControlBMoved(LLUICtrl* ctrl, void* userData) -{ - char const * floatVariableName = (char const *)userData; - LLSliderCtrl* sldrCtrl = static_cast(ctrl); - gPostProcess->tweaks[floatVariableName][2] = sldrCtrl->getValue(); -} - -// Color Moved -void LLFloaterPostProcess::onColorControlIMoved(LLUICtrl* ctrl, void* userData) -{ - char const * floatVariableName = (char const *)userData; - LLSliderCtrl* sldrCtrl = static_cast(ctrl); - gPostProcess->tweaks[floatVariableName][3] = sldrCtrl->getValue(); -} - -void LLFloaterPostProcess::onLoadEffect(LLComboBox* comboBox) -{ - LLSD::String effectName(comboBox->getSelectedValue().asString()); - - gPostProcess->setSelectedEffect(effectName); - - syncMenu(); -} - -void LLFloaterPostProcess::onSaveEffect(LLLineEditor* editBox) -{ - std::string effectName(editBox->getValue().asString()); - - if (gPostProcess->mAllEffects.has(effectName)) - { - LLSD payload; - payload["effect_name"] = effectName; - LLNotificationsUtil::add("PPSaveEffectAlert", LLSD(), payload, boost::bind(&LLFloaterPostProcess::saveAlertCallback, this, _1, _2)); - } - else - { - gPostProcess->saveEffect(effectName); - syncMenu(); - } -} - -void LLFloaterPostProcess::onChangeEffectName(LLUICtrl* ctrl) -{ - // get the combo box and name - LLLineEditor* editBox = getChild("PPEffectNameEditor"); - - // set the parameter's new name - editBox->setValue(ctrl->getValue()); -} - -bool LLFloaterPostProcess::saveAlertCallback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - // if they choose save, do it. Otherwise, don't do anything - if (option == 0) - { - gPostProcess->saveEffect(notification["payload"]["effect_name"].asString()); - - syncMenu(); - } - return false; -} - -void LLFloaterPostProcess::syncMenu() -{ - // add the combo boxe contents - LLComboBox* comboBox = getChild("PPEffectsCombo"); - - comboBox->removeall(); - - LLSD::map_const_iterator currEffect; - for(currEffect = gPostProcess->mAllEffects.beginMap(); - currEffect != gPostProcess->mAllEffects.endMap(); - ++currEffect) - { - comboBox->add(currEffect->first); - } - - // set the current effect as selected. - comboBox->selectByValue(gPostProcess->getSelectedEffect()); - - /// Sync Color Filter Menu - getChild("ColorFilterToggle")->setValue(gPostProcess->tweaks.useColorFilter()); - //getChild("ColorFilterGamma")->setValue(gPostProcess->tweaks.gamma()); - getChild("ColorFilterBrightness")->setValue(gPostProcess->tweaks.brightness()); - getChild("ColorFilterSaturation")->setValue(gPostProcess->tweaks.saturation()); - getChild("ColorFilterContrast")->setValue(gPostProcess->tweaks.contrast()); - getChild("ColorFilterBaseR")->setValue(gPostProcess->tweaks.contrastBaseR()); - getChild("ColorFilterBaseG")->setValue(gPostProcess->tweaks.contrastBaseG()); - getChild("ColorFilterBaseB")->setValue(gPostProcess->tweaks.contrastBaseB()); - getChild("ColorFilterBaseI")->setValue(gPostProcess->tweaks.contrastBaseIntensity()); - - /// Sync Night Vision Menu - getChild("NightVisionToggle")->setValue(gPostProcess->tweaks.useNightVisionShader()); - getChild("NightVisionBrightMult")->setValue(gPostProcess->tweaks.brightMult()); - getChild("NightVisionNoiseSize")->setValue(gPostProcess->tweaks.noiseSize()); - getChild("NightVisionNoiseStrength")->setValue(gPostProcess->tweaks.noiseStrength()); - - /// Sync Bloom Menu - getChild("BloomToggle")->setValue(LLSD(gPostProcess->tweaks.useBloomShader())); - getChild("BloomExtract")->setValue(gPostProcess->tweaks.extractLow()); - getChild("BloomSize")->setValue(gPostProcess->tweaks.bloomWidth()); - getChild("BloomStrength")->setValue(gPostProcess->tweaks.bloomStrength()); -} diff --git a/indra/newview/llfloaterpostprocess.h b/indra/newview/llfloaterpostprocess.h deleted file mode 100644 index 50b48d84107..00000000000 --- a/indra/newview/llfloaterpostprocess.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file llfloaterpostprocess.h - * @brief LLFloaterPostProcess class definition - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLFLOATERPOSTPROCESS_H -#define LL_LLFLOATERPOSTPROCESS_H - -#include "llfloater.h" - -class LLButton; -class LLComboBox; -class LLLineEditor; -class LLSliderCtrl; -class LLTabContainer; -class LLPanelPermissions; -class LLPanelObject; -class LLPanelVolume; -class LLPanelContents; -class LLPanelFace; - -/** - * Menu for adjusting the post process settings of the world - */ -class LLFloaterPostProcess : public LLFloater -{ -public: - - LLFloaterPostProcess(const LLSD& key); - virtual ~LLFloaterPostProcess(); - bool postBuild(); - - /// post process callbacks - static void onBoolToggle(LLUICtrl* ctrl, void* userData); - static void onFloatControlMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlRMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlGMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlBMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlIMoved(LLUICtrl* ctrl, void* userData); - void onLoadEffect(LLComboBox* comboBox); - void onSaveEffect(LLLineEditor* editBox); - void onChangeEffectName(LLUICtrl* ctrl); - - /// prompts a user when overwriting an effect - bool saveAlertCallback(const LLSD& notification, const LLSD& response); - - /// sync up sliders - void syncMenu(); -}; - -#endif diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index eda93e3e79d..b63aa0997b2 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -334,11 +334,11 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata) } else if ("copy_slurl" == action) { - boost::function copy_slurl_cb = [](LLLandmark* landmark) + std::function copy_slurl_cb = [](LLLandmark* landmark) { LLVector3d global_pos; landmark->getGlobalPos(global_pos); - boost::function copy_slurl_to_clipboard_cb = [](const std::string& slurl) + std::function copy_slurl_to_clipboard_cb = [](const std::string& slurl) { gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl)); LLSD args; diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index a9e860d2ef0..2ddc09736f2 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -1309,7 +1309,7 @@ void LLPanelOutfitEdit::showFilteredWearablesListView(LLWearableType::EType type showWearablesListView(); //e_list_view_item_type implicitly contains LLWearableType::EType starting from LVIT_SHAPE - applyListViewFilter(static_cast(LVIT_SHAPE + type)); + applyListViewFilter(static_cast(static_cast(LVIT_SHAPE) + static_cast(type))); mWearableItemsList->setMenuWearableType(type); } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 3786a9b1609..6f26c2e2e76 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -182,7 +182,6 @@ #include "llnamelistctrl.h" #include "llnamebox.h" #include "llnameeditor.h" -#include "llpostprocess.h" #include "llagentlanguage.h" #include "llwearable.h" #include "llinventorybridge.h" @@ -1347,10 +1346,6 @@ bool idle_startup() LLDrawable::initClass(); do_startup_frame(); - // init the shader managers - LLPostProcess::initClass(); - do_startup_frame(); - LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml"); do_startup_frame(); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 4c408ec17d1..eaff660a781 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -55,7 +55,6 @@ #include "llmemory.h" #include "llparcel.h" #include "llperfstats.h" -#include "llpostprocess.h" #include "llrender.h" #include "llscenemonitor.h" #include "llsdjson.h" diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 3b35ca8db1b..daf3922aebf 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -119,7 +119,6 @@ #include "llfloaterpay.h" #include "llfloaterperformance.h" #include "llfloaterperms.h" -#include "llfloaterpostprocess.h" #include "llfloaterpreference.h" #include "llfloaterpreferencesgraphicsadvanced.h" #include "llfloaterpreferenceviewadvanced.h" @@ -367,7 +366,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("emoji_picker", "floater_emoji_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 89861d74bc5..035a8f5b292 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1735,6 +1735,13 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ } else { +#if LL_LINUX + if(plugin_basename == "media_plugin_gstreamer10" && gSavedSettings.getBOOL("MediaPluginForceVLC")) + { + plugin_basename = "media_plugin_libvlc"; + } +#endif + std::string launcher_name = gDirUtilp->getLLPluginLauncher(); std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename); @@ -1749,9 +1756,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ } else if(LLFile::stat(plugin_name, &s)) { -#if !LL_LINUX LL_WARNS_ONCE("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; -#endif } else { @@ -1804,9 +1809,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ } } } -#if !LL_LINUX LL_WARNS_ONCE("Plugin") << "plugin initialization failed for mime type: " << media_type << LL_ENDL; -#endif if(gAgent.isInitialized()) { diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 801ff3c2122..10ba93df6d2 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -138,11 +138,11 @@ std::queue LLFilePickerThread::sDeadQ; void LLFilePickerThread::getFile() { -#if LL_WINDOWS +#if LL_DARWIN || LL_SDL_WINDOW + runModeless(); +#elif LL_WINDOWS // Todo: get rid of LLFilePickerThread and make this modeless start(); -#elif LL_DARWIN - runModeless(); #else run(); #endif diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 670a3b29395..7dfc5150c42 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -188,7 +188,6 @@ #include "llviewerjoystick.h" #include "llviewermenufile.h" // LLFilePickerReplyThread #include "llviewernetwork.h" -#include "llpostprocess.h" #include "llfloaterimnearbychat.h" #include "llagentui.h" #include "llwearablelist.h" @@ -5647,11 +5646,6 @@ void* LLViewerWindow::getPlatformWindow() const return mWindow->getPlatformWindow(); } -void* LLViewerWindow::getMediaWindow() const -{ - return mWindow->getMediaWindow(); -} - void LLViewerWindow::focusClient() const { return mWindow->focusClient(); @@ -5873,11 +5867,6 @@ void LLViewerWindow::stopGL() gBox.cleanupGL(); - if(gPostProcess) - { - gPostProcess->invalidate(); - } - gTextureList.destroyGL(); stop_glerror(); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 61aa84394c2..00413ce1416 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -270,7 +270,6 @@ class LLViewerWindow : public LLWindowCallbacks LLWindow* getWindow() const { return mWindow; } void* getPlatformWindow() const; - void* getMediaWindow() const; void focusClient() const; LLCoordGL getLastMouse() const { return mLastMousePoint; } diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 7fbcb5fc048..5b24d46bb0b 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -218,7 +218,7 @@ LLXMLRPCTransaction::Impl::Impl mCertStore = gSavedSettings.getString("CertStore"); httpOpts->setSSLVerifyPeer(vefifySSLCert); - httpOpts->setSSLVerifyHost(vefifySSLCert ? 2 : 0); + httpOpts->setSSLVerifyHost(vefifySSLCert); // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); diff --git a/indra/newview/skins/default/xui/en/floater_post_process.xml b/indra/newview/skins/default/xui/en/floater_post_process.xml deleted file mode 100644 index 37339f79c87..00000000000 --- a/indra/newview/skins/default/xui/en/floater_post_process.xml +++ /dev/null @@ -1,426 +0,0 @@ - - - - - - - Brightness - - - - Saturation - - - - Contrast - - - - Contrast Base Color - - - - - - - - - - Light Amplification Multiple - - - - Noise Size - - - - Noise Strength - - - - - - - Luminosity Extraction - - - - Bloom Size - - - - Bloom Strength - - - - -