diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4c8d98ce2f6..2101b9b5e83 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -86,7 +86,7 @@ jobs: variants: ${{ matrix.configuration }} steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} @@ -95,14 +95,14 @@ jobs: with: python-version: "3.11" - name: Checkout build variables - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: secondlife/build-variables ref: master path: .build-variables - name: Checkout master-message-template - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: secondlife/master-message-template path: .master-message-template @@ -112,7 +112,7 @@ jobs: - name: Cache autobuild packages id: cache-installables - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .autobuild-installables key: ${{ runner.os }}-64-${{ matrix.configuration }}-${{ hashFiles('autobuild.xml') }} @@ -265,7 +265,7 @@ jobs: - name: Upload executable if: steps.build.outputs.viewer_app - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: "${{ steps.build.outputs.artifact }}-app" path: | @@ -275,13 +275,13 @@ jobs: # artifact for that too. - name: Upload symbol file if: steps.build.outputs.symbolfile - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: "${{ steps.build.outputs.artifact }}-symbols" path: ${{ steps.build.outputs.symbolfile }} - name: Upload metadata - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: "${{ steps.build.outputs.artifact }}-metadata" # emitted by build.sh, possibly multiple lines @@ -289,7 +289,7 @@ jobs: ${{ steps.build.outputs.metadata }} - name: Upload physics package - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 # should only be set for viewer-private if: matrix.configuration == 'Release' && steps.build.outputs.physicstpv with: @@ -370,13 +370,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Download viewer exe - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v7 with: name: Windows-app path: _artifacts - name: Download Windows Symbols if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v7 with: name: Windows-symbols - name: Extract viewer pdb @@ -409,7 +409,7 @@ jobs: steps: - name: Download Mac Symbols if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v7 with: name: macOS-symbols - name: Post Mac symbols @@ -431,11 +431,11 @@ jobs: runs-on: ubuntu-latest if: needs.setup.outputs.release_run steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v7 with: pattern: "*-installer" - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v7 with: pattern: "*-metadata" diff --git a/.github/workflows/cla.yaml b/.github/workflows/cla.yaml index 5b31c584d50..800f3c42d1c 100644 --- a/.github/workflows/cla.yaml +++ b/.github/workflows/cla.yaml @@ -23,4 +23,4 @@ jobs: path-to-signatures: signatures.json remote-organization-name: secondlife remote-repository-name: cla-signatures - allowlist: callum@mbp.localdomain,rye@lindenlab.com,rye,bot* + allowlist: callum@mbp.localdomain,rye@lindenlab.com,rye,signal@lindenlab.com,dependabot*,bot* diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml index 8f942fa11bc..93bcafdea85 100644 --- a/.github/workflows/pre-commit.yaml +++ b/.github/workflows/pre-commit.yaml @@ -11,7 +11,7 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: python-version: 3.x diff --git a/autobuild.xml b/autobuild.xml index 7333583415a..6e48cbf5093 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -106,11 +106,11 @@ archive hash - a4553df5b8fde2e9cd54ebb94c6efb8eb5fe3c38 + 61cc299413a32350175cf7139f64388d3d096ec7 hash_algorithm sha1 url - https://github.com/secondlife/3p-boost/releases/download/v1.86.0-be1a669/boost-1.86-darwin64-13246092114.tar.zst + https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-darwin64-20977261894.tar.zst name darwin64 @@ -120,11 +120,11 @@ archive hash - 4a2a19dc5cb555e157ad894ba917f5a83a35b20d + 6b93e323284bfab8ec20a7f3bc740c6915980bf8 hash_algorithm sha1 url - https://github.com/secondlife/3p-boost/releases/download/v1.86.0-be1a669/boost-1.86-linux64-13246092114.tar.zst + https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-linux64-20977261894.tar.zst name linux64 @@ -134,11 +134,11 @@ archive hash - 8a1fa9366bfe49009286e4805d7aaedb7c3df82e + c543437ca30a63dcd2538fffa89a43ef43f625fb hash_algorithm sha1 url - https://github.com/secondlife/3p-boost/releases/download/v1.86.0-be1a669/boost-1.86-windows64-13246092114.tar.zst + https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-windows64-20977261894.tar.zst name windows64 @@ -151,7 +151,7 @@ copyright (see individual source files) version - 1.86 + 1.90.0-c7a9feb name boost description @@ -212,11 +212,11 @@ archive hash - bf2fe4e8272e990bc8687b3b37bf4bb2b2ad6eb4 + 9710f82a237b95aaafbbcf708b89f6015b80d85f hash_algorithm sha1 url - https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-darwin64-13259816660.tar.zst + https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-darwin64-20980076767.tar.zst name darwin64 @@ -226,11 +226,11 @@ archive hash - 118e509ca464182ef4b94ee8c4aa5b14a6c52a94 + 6a1725b1bc13634eb4dd872a4f83c3f16497475f hash_algorithm sha1 url - https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-linux64-13259816660.tar.zst + https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-linux64-20980076767.tar.zst name linux64 @@ -240,11 +240,11 @@ archive hash - d7aee1b2ec17bd88a2c27359281b58a11ec52d48 + ba9eeb62ae3046d91f9e061db823c1863623b017 hash_algorithm sha1 url - https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-windows64-13259816660.tar.zst + https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-windows64-20980076767.tar.zst name windows64 @@ -257,7 +257,7 @@ copyright Copyright 2006 Sony Computer Entertainment Inc. version - 2.3.0-r10 + 2.3.0-r11 name colladadom @@ -328,11 +328,11 @@ archive hash - e742b1e2d0a58d607b023bf55411041ac65e8a76 + 5eab8167cec442e8c156bb653012d7544cca6037 hash_algorithm sha1 url - https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-darwin64-13259824618.tar.zst + https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-darwin64-20982000504.tar.zst name darwin64 @@ -342,11 +342,11 @@ archive hash - 49621c70f385d37c95bcb69a9a24d86ac25f4781 + 3465bbe70cfba2814b1fd52094c62804f4067490 hash_algorithm sha1 url - https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-linux64-13259824618.tar.zst + https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-linux64-20982000504.tar.zst name linux64 @@ -356,11 +356,11 @@ archive hash - 2522201692116cf0adb7203e169be9126885108c + 0e64e20945eeb19259abf8e78400eb492e31eda7 hash_algorithm sha1 url - https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-windows64-13259824618.tar.zst + https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-windows64-20982000504.tar.zst name windows64 @@ -373,7 +373,7 @@ copyright Copyright (c) 1996 - 2014, Daniel Stenberg, (daniel@haxx.se). version - 7.54.1-13259824618 + 7.54.1-20982000504 name curl description @@ -634,11 +634,11 @@ archive hash - 5e6c7b9aaf73d90d7feab846a4024193c48eff6c + 550a90bca35bdbbd615afb1a1c02383cb3b6edbe hash_algorithm sha1 url - https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-darwin64-13259804885.tar.zst + https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-darwin64-20935810762.tar.zst name darwin64 @@ -648,11 +648,11 @@ archive hash - a9a3c371958e64a49b07d7be8f59218dfd6b0352 + f52b05392962cb6a8e5f534d8687faa525d4960a hash_algorithm sha1 url - https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-linux64-13259804885.tar.zst + https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-linux64-20935810762.tar.zst name linux64 @@ -662,11 +662,11 @@ archive hash - ad7fbc4a01607ec43d86035a49dadd43d6f2a4e5 + 3c30052adcbfec572562bb1e7927d7a8f4d93f3d hash_algorithm sha1 url - https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-windows64-13259804885.tar.zst + https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-windows64-20935810762.tar.zst name windows64 @@ -679,7 +679,7 @@ copyright Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg. version - 2.13.3-r3 + 2.13.3-r4 name freetype description @@ -1226,11 +1226,11 @@ archive hash - a453355ee032f79aea4142218a957085a22c7656 + 6fa10d5f44601dda6efc3eda1a9dab22525e7a9a hash_algorithm sha1 url - https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-darwin64-13246065198.tar.zst + https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-darwin64-20934739343.tar.zst name darwin64 @@ -1240,11 +1240,11 @@ archive hash - 75c7608646c9f5b99b1a9e3946326e2804a304d7 + 112b7f46f5923e6418dfa4bc13ebe2db6911c9b9 hash_algorithm sha1 url - https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-linux64-13246065198.tar.zst + https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-linux64-20934739343.tar.zst name linux64 @@ -1254,11 +1254,11 @@ archive hash - 09af51774c4ee7c03fe67a87dfc52e846aa625ea + 2731c45f1e62e33b8612b3ee2b9c4cb39dafbfe2 hash_algorithm sha1 url - https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-windows64-13246065198.tar.zst + https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-windows64-20934739343.tar.zst name windows64 @@ -1271,7 +1271,7 @@ copyright Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson version - 1.6.44-r2 + 1.6.53-eea12b7 name libpng description @@ -1316,11 +1316,11 @@ archive hash - 372c92936d940b1cfb5ba34310691d4bb435c161 + c1ad7ff9ec91049c93d2dcd832f81a00f8f4b4b9 hash_algorithm sha1 url - https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-darwin64-13246071272.tar.zst + https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-darwin64-20936141417.tar.zst name darwin64 @@ -1330,11 +1330,11 @@ archive hash - ba6fbc34112b1acab1c8615dcd13de983f3678d3 + 7fc2df91648661468a82754b26fd7dedfbef1d39 hash_algorithm sha1 url - https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-linux64-13246071272.tar.zst + https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-linux64-20936141417.tar.zst name linux64 @@ -1344,11 +1344,11 @@ archive hash - 71968c4b621636e8ae0c5680e631f4aa67561944 + 84828c26b67c33f0d3e565718943aa339582b34f hash_algorithm sha1 url - https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-windows64-13246071272.tar.zst + https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-windows64-20936141417.tar.zst name windows64 @@ -1361,7 +1361,7 @@ copyright Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved. version - 2.13.5-r2 + 2.13.9-d53cd6f name libxml2 description @@ -1547,11 +1547,11 @@ archive hash - 874a7d2bc843554aa4facd03b3a6d681f2b5150c + 3692af717636da9c2b1e0f13eb084ce022b67f6c hash_algorithm sha1 url - https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-darwin64-11968851109.tar.zst + https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-darwin64-20867041007.tar.zst name darwin64 @@ -1561,11 +1561,11 @@ archive hash - 31a537f1a3d38ef85443214315111dd56a534d9a + 22ad1be39a1196a1ca3902ba936460cb69252b9c hash_algorithm sha1 url - https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-linux64-11968851109.tar.zst + https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-linux64-20867041007.tar.zst name linux64 @@ -1575,11 +1575,11 @@ archive hash - 6fd727a9ccb3e7a6c6b4ffef8179e266c032eb3e + 2c9769f31da5de3920d7ee400d280398c911a30f hash_algorithm sha1 url - https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-windows64-11968851109.tar.zst + https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-windows64-20867041007.tar.zst name windows64 @@ -1671,11 +1671,11 @@ archive hash - b628d088e1f368a0cd51a6b66292aaf9a025e2d4 + 85179317015c5c91986000d69c9f61a01af7617f hash_algorithm sha1 url - https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-darwin64-13246046977.tar.zst + https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-darwin64-20933148061.tar.zst name darwin64 @@ -1685,11 +1685,11 @@ archive hash - 492ce9175b730d43df63821c4481685e035af623 + ef1524f507f44fed6f1c1f00ae274ddb8a1ac359 hash_algorithm sha1 url - https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-linux64-13246046977.tar.zst + https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-linux64-20933148061.tar.zst name linux64 @@ -1699,11 +1699,11 @@ archive hash - 58773e707ff3490822b7b8217d7729ade2186632 + 90be39cf789b596377458f1ea78f415a9c281a8c hash_algorithm sha1 url - https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-windows64-13246046977.tar.zst + https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-windows64-20933148061.tar.zst name windows64 @@ -1716,7 +1716,7 @@ copyright This project uses the zlib license. Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler version - 4.0.7-r3 + 4.0.7-r4 name minizip-ng canonical_repo @@ -2079,11 +2079,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 157193699127ac5056c5fc1a410f9c98d39731e2 + e08f640fb423f878c288426c836189b30b0c8ad0 hash_algorithm sha1 url - https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-darwin64-13246054022.tar.zst + https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-darwin64-20981673556.tar.zst name darwin64 @@ -2093,11 +2093,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 2e29c127dbd002d64ae55bc000f8b6ed0249fad7 + d83a1e910762b792c90550ce2b8f51f9aaec7570 hash_algorithm sha1 url - https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-linux64-13246054022.tar.zst + https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-linux64-20981673556.tar.zst name linux64 @@ -2107,11 +2107,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - ae9ced89051e03a99628c99b9ac78530fdea1e5a + eec78c22e2d1eecf375aa0c6eff08fe67d2316f4 hash_algorithm sha1 url - https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-windows64-13246054022.tar.zst + https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-windows64-20981673556.tar.zst name windows64 @@ -2124,7 +2124,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors copyright Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved; Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) version - 1.1.1w-r3 + 1.1.1w-r4 name openssl description @@ -2731,11 +2731,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - e363e3b889c52fda7601d7aeaa9832307034651e + 4906257288c61b14d2e16116fc3139af35d3374f hash_algorithm sha1 url - https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-darwin64-13183604450.tar.zst + https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-darwin64-20930307098.tar.zst name darwin64 @@ -2745,11 +2745,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 3cdd52f7fb3691789d50f0b40ed6f5642321ff32 + 2b81a6a4ebd9ae5555d48b52eea7c2d875d68f60 hash_algorithm sha1 url - https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-linux64-13183604450.tar.zst + https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-linux64-20930307098.tar.zst name linux64 @@ -2759,11 +2759,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - e802a28139328bb2421ad39e13d996d350d8106d + e2e0f964ba44fe2e6428e1e7ca262a3f80d92e65 hash_algorithm sha1 url - https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-windows64-13183604450.tar.zst + https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-windows64-20930307098.tar.zst name windows64 @@ -2776,7 +2776,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors copyright Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler version - 2.2.3-dev0.g8aa13e3.d20250206 + 2.2.5-0d88d03 name zlib-ng canonical_repo diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index b57c33c3e00..3bea85f3eaa 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -20,48 +20,42 @@ if (WINDOWS) find_library(BOOST_CONTEXT_LIBRARY NAMES + libboost_context libboost_context-mt libboost_context-mt${addrsfx} PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) find_library(BOOST_FIBER_LIBRARY NAMES + libboost_fiber libboost_fiber-mt libboost_fiber-mt${addrsfx} PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) find_library(BOOST_FILESYSTEM_LIBRARY NAMES + libboost_filesystem 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 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 libboost_thread-mt libboost_thread-mt${addrsfx} PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) find_library(BOOST_URL_LIBRARY NAMES + libboost_url libboost_url-mt libboost_url-mt${addrsfx} PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) @@ -70,48 +64,42 @@ else (WINDOWS) find_library(BOOST_CONTEXT_LIBRARY NAMES + boost_context boost_context-mt boost_context-mt${addrsfx} PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) find_library(BOOST_FIBER_LIBRARY NAMES + boost_fiber boost_fiber-mt boost_fiber-mt${addrsfx} PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) find_library(BOOST_FILESYSTEM_LIBRARY NAMES + boost_filesystem 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 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 boost_thread-mt boost_thread-mt${addrsfx} PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) find_library(BOOST_URL_LIBRARY NAMES + boost_url boost_url-mt boost_url-mt${addrsfx} PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) @@ -123,8 +111,6 @@ target_link_libraries(ll::boost INTERFACE ${BOOST_CONTEXT_LIBRARY} ${BOOST_FILESYSTEM_LIBRARY} ${BOOST_PROGRAMOPTIONS_LIBRARY} - ${BOOST_REGEX_LIBRARY} - ${BOOST_SYSTEM_LIBRARY} ${BOOST_THREAD_LIBRARY} ${BOOST_URL_LIBRARY}) diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake index 7cce190f6a5..428f9e33267 100644 --- a/indra/cmake/Python.cmake +++ b/indra/cmake/Python.cmake @@ -1,57 +1,18 @@ -# -*- cmake -*- - -set(PYTHONINTERP_FOUND) - -if (DEFINED ENV{PYTHON}) - # Allow python executable to be explicitly set - set(python "$ENV{PYTHON}") - set(PYTHONINTERP_FOUND ON) -elseif (WINDOWS) - # On Windows, explicitly avoid Cygwin Python. - - # if the user has their own version of Python installed, prefer that - 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) - list(APPEND regpaths "[${hive}\\SOFTWARE\\Python\\PythonCore\\${pyver}\\InstallPath]") - endforeach() - endforeach() - - # TODO: This logic has the disadvantage that if you have multiple versions - # of Python installed, the selected path won't necessarily be the newest - - # e.g. this GLOB will prefer Python310 to Python311. But since pymaybe is - # checked AFTER the registry entries, this will only surface as a problem if - # no installed Python appears in the registry. - file(GLOB pymaybe - "$ENV{PROGRAMFILES}/Python*" -## "$ENV{PROGRAMFILES(X86)}/Python*" - # The Windows environment variable is in fact as shown above, but CMake - # disallows querying an environment variable containing parentheses - - # thanks, Windows. Fudge by just appending " (x86)" to $PROGRAMFILES and - # hoping for the best. - "$ENV{PROGRAMFILES} (x86)/Python*" - "c:/Python*") - - find_program(python - NAMES python3.exe python.exe - NO_DEFAULT_PATH # added so that cmake does not find cygwin python - PATHS - ${regpaths} - ${pymaybe} - ) - find_package(Python3 COMPONENTS Interpreter) -else() - find_program(python python3) - - if (python) - set(PYTHONINTERP_FOUND ON) - endif (python) -endif (DEFINED ENV{PYTHON}) - -if (NOT python) - message(FATAL_ERROR "No Python interpreter found") -endif (NOT python) - -set(PYTHON_EXECUTABLE "${python}" CACHE FILEPATH "Python interpreter for builds") +# Allow explicit Python path via environment variable +if(DEFINED ENV{PYTHON}) + set(Python3_ROOT_DIR "$ENV{PYTHON}") +endif() + +# On Windows, prefer registry entries to avoid Cygwin/MSYS Python +# The registry is searched first by default, which finds native Windows Python +# installations rather than Cygwin/MSYS Python +if(WINDOWS) + set(Python3_FIND_REGISTRY FIRST CACHE STRING "Python search order") +endif() + +# Find Python 3 interpreter +find_package(Python3 REQUIRED COMPONENTS Interpreter) + +# Set legacy variable name for compatibility with existing code +set(PYTHON_EXECUTABLE "${Python3_EXECUTABLE}" CACHE FILEPATH "Python interpreter for builds") mark_as_advanced(PYTHON_EXECUTABLE) diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 7f7eaf18554..19e4e8ed9de 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -1424,6 +1424,12 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC size_t mem_size = pixels * bytes_per_pixel; alpha_data = (U8*)ll_aligned_malloc_32(mem_size); + if (!alpha_data) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS() << "Failed to allocate memory for morph texture: " << (S32)(mem_size) << LL_ENDL; + return; + } bool skip_readback = LLRender::sNsightDebugSupport; // nSight doesn't support use of glReadPixels @@ -1433,6 +1439,12 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC { // work-around for broken intel drivers which cannot do glReadPixels on an RGBA FBO // returning only the alpha portion without locking up downstream U8* temp = (U8*)ll_aligned_malloc_32(mem_size << 2); // allocate same size, but RGBA + if (!temp) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS() << "Failed to allocate temporary memory for morph texture readback: " << (S32)(mem_size << 2) << LL_ENDL; + return; + } if (bound_target) { @@ -1469,6 +1481,12 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC // We just want GL_ALPHA, but that isn't supported in OGL core profile 4. static const size_t TEMP_BYTES_PER_PIXEL = 4; U8* temp_data = (U8*)ll_aligned_malloc_32(mem_size * TEMP_BYTES_PER_PIXEL); + if (!temp_data) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS() << "Failed to allocate temporary memory for morph texture: " << (S32)(mem_size * TEMP_BYTES_PER_PIXEL) << LL_ENDL; + return; + } glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, temp_data); for (size_t pixel = 0; pixel < pixels; pixel++) { alpha_data[pixel] = temp_data[(pixel * TEMP_BYTES_PER_PIXEL) + 3]; diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index 613c4081571..6f2f7eae61d 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -225,6 +225,7 @@ void LLAudioEngine::updateChannels() void LLAudioEngine::idle() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; // "Update" all of our audio sources, clean up dead ones. // Primarily does position updating, cleanup of unused audio sources. // Also does regeneration of the current priority of each audio source. diff --git a/indra/llcharacter/CMakeLists.txt b/indra/llcharacter/CMakeLists.txt index bc45eb474a4..c6513cdb667 100644 --- a/indra/llcharacter/CMakeLists.txt +++ b/indra/llcharacter/CMakeLists.txt @@ -17,14 +17,12 @@ set(llcharacter_SOURCE_FILES lljointsolverrp3.cpp llkeyframefallmotion.cpp llkeyframemotion.cpp - llkeyframemotionparam.cpp llkeyframestandmotion.cpp llkeyframewalkmotion.cpp llmotioncontroller.cpp llmotion.cpp llmultigesture.cpp llpose.cpp - llstatemachine.cpp lltargetingmotion.cpp llvisualparam.cpp ) @@ -45,14 +43,12 @@ set(llcharacter_HEADER_FILES lljointstate.h llkeyframefallmotion.h llkeyframemotion.h - llkeyframemotionparam.h llkeyframestandmotion.h llkeyframewalkmotion.h llmotion.h llmotioncontroller.h llmultigesture.h llpose.h - llstatemachine.h lltargetingmotion.h llvisualparam.h ) diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp deleted file mode 100644 index e4552b96c94..00000000000 --- a/indra/llcharacter/llkeyframemotionparam.cpp +++ /dev/null @@ -1,436 +0,0 @@ -/** - * @file llkeyframemotionparam.cpp - * @brief Implementation of LLKeyframeMotion class. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -//----------------------------------------------------------------------------- -// Header Files -//----------------------------------------------------------------------------- -#include "linden_common.h" - -#include "llkeyframemotionparam.h" -#include "llcharacter.h" -#include "llmath.h" -#include "m3math.h" -#include "lldir.h" -#include "llanimationstates.h" - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam class -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam() -// Class Constructor -//----------------------------------------------------------------------------- -LLKeyframeMotionParam::LLKeyframeMotionParam( const LLUUID &id) : LLMotion(id) -{ - mDefaultKeyframeMotion = NULL; - mCharacter = NULL; - - mEaseInDuration = 0.f; - mEaseOutDuration = 0.f; - mDuration = 0.f; - mPriority = LLJoint::LOW_PRIORITY; -} - - -//----------------------------------------------------------------------------- -// ~LLKeyframeMotionParam() -// Class Destructor -//----------------------------------------------------------------------------- -LLKeyframeMotionParam::~LLKeyframeMotionParam() -{ - for (motion_map_t::value_type& motion_pair : mParameterizedMotions) - { - motion_list_t& motionList = motion_pair.second; - for (const ParameterizedMotion& paramMotion : motionList) - { - delete paramMotion.mMotion; - } - motionList.clear(); - } - mParameterizedMotions.clear(); -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onInitialize(LLCharacter *character) -//----------------------------------------------------------------------------- -LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *character) -{ - mCharacter = character; - - if (!loadMotions()) - { - return STATUS_FAILURE; - } - - for (motion_map_t::value_type& motion_pair : mParameterizedMotions) - { - motion_list_t& motionList = motion_pair.second; - for (const ParameterizedMotion& paramMotion : motionList) - { - LLMotion* motion = paramMotion.mMotion; - motion->onInitialize(character); - - if (motion->getDuration() > mEaseInDuration) - { - mEaseInDuration = motion->getEaseInDuration(); - } - - if (motion->getEaseOutDuration() > mEaseOutDuration) - { - mEaseOutDuration = motion->getEaseOutDuration(); - } - - if (motion->getDuration() > mDuration) - { - mDuration = motion->getDuration(); - } - - if (motion->getPriority() > mPriority) - { - mPriority = motion->getPriority(); - } - - LLPose *pose = motion->getPose(); - - mPoseBlender.addMotion(motion); - for (LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState()) - { - LLPose *blendedPose = mPoseBlender.getBlendedPose(); - blendedPose->addJointState(jsp); - } - } - } - - return STATUS_SUCCESS; -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onActivate() -//----------------------------------------------------------------------------- -bool LLKeyframeMotionParam::onActivate() -{ - for (motion_map_t::value_type& motion_pair : mParameterizedMotions) - { - motion_list_t& motionList = motion_pair.second; - for (const ParameterizedMotion& paramMotion : motionList) - { - paramMotion.mMotion->activate(mActivationTimestamp); - } - } - return true; -} - - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onUpdate() -//----------------------------------------------------------------------------- -bool LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask) -{ - LL_PROFILE_ZONE_SCOPED; - F32 weightFactor = 1.f / (F32)mParameterizedMotions.size(); - - // zero out all pose weights - for (motion_map_t::value_type& motion_pair : mParameterizedMotions) - { - motion_list_t& motionList = motion_pair.second; - for (const ParameterizedMotion& paramMotion : motionList) - { -// LL_INFOS() << "Weight for pose " << paramMotion.mMotion->getName() << " is " << paramMotion.mMotion->getPose()->getWeight() << LL_ENDL; - paramMotion.mMotion->getPose()->setWeight(0.f); - } - } - - - for (motion_map_t::value_type& motion_pair : mParameterizedMotions) - { - const std::string& paramName = motion_pair.first; - F32* paramValue = (F32 *)mCharacter->getAnimationData(paramName); - if (NULL == paramValue) // unexpected, but... - { - LL_WARNS() << "paramValue == NULL" << LL_ENDL; - continue; - } - - // DANGER! Do not modify mParameterizedMotions while using these pointers! - const ParameterizedMotion* firstMotion = NULL; - const ParameterizedMotion* secondMotion = NULL; - - motion_list_t& motionList = motion_pair.second; - for (const ParameterizedMotion& paramMotion : motionList) - { - paramMotion.mMotion->onUpdate(time, joint_mask); - - F32 distToParam = paramMotion.mParam - *paramValue; - - if ( distToParam <= 0.f) - { - // keep track of the motion closest to the parameter value - firstMotion = ¶mMotion; - } - else - { - // we've passed the parameter value - // so store the first motion we find as the second one we want to blend... - if (firstMotion && !secondMotion ) - { - secondMotion = ¶mMotion; - } - //...or, if we've seen no other motion so far, make sure we blend to this only - else if (!firstMotion) - { - firstMotion = ¶mMotion; - secondMotion = ¶mMotion; - } - } - } - - LLPose *firstPose; - LLPose *secondPose; - - if (firstMotion) - firstPose = firstMotion->mMotion->getPose(); - else - firstPose = NULL; - - if (secondMotion) - secondPose = secondMotion->mMotion->getPose(); - else - secondPose = NULL; - - // now modify weight of the subanim (only if we are blending between two motions) - if (firstMotion && secondMotion) - { - if (firstMotion == secondMotion) - { - firstPose->setWeight(weightFactor); - } - else if (firstMotion->mParam == secondMotion->mParam) - { - firstPose->setWeight(0.5f * weightFactor); - secondPose->setWeight(0.5f * weightFactor); - } - else - { - F32 first_weight = 1.f - - ((llclamp(*paramValue - firstMotion->mParam, 0.f, (secondMotion->mParam - firstMotion->mParam))) / - (secondMotion->mParam - firstMotion->mParam)); - first_weight = llclamp(first_weight, 0.f, 1.f); - - F32 second_weight = 1.f - first_weight; - - firstPose->setWeight(first_weight * weightFactor); - secondPose->setWeight(second_weight * weightFactor); - -// LL_INFOS() << "Parameter " << *paramName << ": " << *paramValue << LL_ENDL; -// LL_INFOS() << "Weights " << firstPose->getWeight() << " " << secondPose->getWeight() << LL_ENDL; - } - } - else if (firstMotion && !secondMotion) - { - firstPose->setWeight(weightFactor); - } - } - - // blend poses - mPoseBlender.blendAndApply(); - - LL_INFOS() << "Param Motion weight " << mPoseBlender.getBlendedPose()->getWeight() << LL_ENDL; - - return true; -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onDeactivate() -//----------------------------------------------------------------------------- -void LLKeyframeMotionParam::onDeactivate() -{ - for (motion_map_t::value_type& motion_pair : mParameterizedMotions) - { - motion_list_t& motionList = motion_pair.second; - for (const ParameterizedMotion& paramMotion : motionList) - { - paramMotion.mMotion->onDeactivate(); - } - } -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::addKeyframeMotion() -//----------------------------------------------------------------------------- -bool LLKeyframeMotionParam::addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value) -{ - LLMotion *newMotion = mCharacter->createMotion( id ); - - if (!newMotion) - { - return false; - } - - newMotion->setName(name); - - // now add motion to this list - mParameterizedMotions[param].insert(ParameterizedMotion(newMotion, value)); - - return true; -} - - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::setDefaultKeyframeMotion() -//----------------------------------------------------------------------------- -void LLKeyframeMotionParam::setDefaultKeyframeMotion(char *name) -{ - for (motion_map_t::value_type& motion_pair : mParameterizedMotions) - { - motion_list_t& motionList = motion_pair.second; - for (const ParameterizedMotion& paramMotion : motionList) - { - if (paramMotion.mMotion->getName() == name) - { - mDefaultKeyframeMotion = paramMotion.mMotion; - } - } - } -} - -//----------------------------------------------------------------------------- -// loadMotions() -//----------------------------------------------------------------------------- -bool LLKeyframeMotionParam::loadMotions() -{ - //------------------------------------------------------------------------- - // Load named file by concatenating the character prefix with the motion name. - // Load data into a buffer to be parsed. - //------------------------------------------------------------------------- - //std::string path = gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix()) - // + "_" + getName() + ".llp"; - //RN: deprecated unused reference to "motion" directory - std::string path; - - - //------------------------------------------------------------------------- - // open the file - //------------------------------------------------------------------------- - S32 fileSize = 0; - LLAPRFile infile ; - infile.open(path, LL_APR_R, NULL, &fileSize); - apr_file_t* fp = infile.getFileHandle() ; - if (!fp || fileSize == 0) - { - LL_INFOS() << "ERROR: can't open: " << path << LL_ENDL; - return false; - } - - // allocate a text buffer - std::vector text(fileSize+1); - - //------------------------------------------------------------------------- - // load data from file into buffer - //------------------------------------------------------------------------- - bool error = false; - char *p = &text[0]; - while ( 1 ) - { - if (apr_file_eof(fp) == APR_EOF) - { - break; - } - if (apr_file_gets(p, 1024, fp) != APR_SUCCESS) - { - error = true; - break; - } - while ( *(++p) ) - ; - } - - //------------------------------------------------------------------------- - // close the file - //------------------------------------------------------------------------- - infile.close(); - - //------------------------------------------------------------------------- - // check for error - //------------------------------------------------------------------------- - llassert( p <= (&text[0] + fileSize) ); - - if ( error ) - { - LL_INFOS() << "ERROR: error while reading from " << path << LL_ENDL; - return false; - } - - LL_INFOS() << "Loading parametric keyframe data for: " << getName() << LL_ENDL; - - //------------------------------------------------------------------------- - // parse the text and build keyframe data structures - //------------------------------------------------------------------------- - p = &text[0]; - S32 num; - char strA[80]; /* Flawfinder: ignore */ - char strB[80]; /* Flawfinder: ignore */ - F32 floatA = 0.0f; - - - //------------------------------------------------------------------------- - // get priority - //------------------------------------------------------------------------- - bool isFirstMotion = true; - num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */ - - while(1) - { - if (num == 0 || num == EOF) break; - if ((num != 3)) - { - LL_INFOS() << "WARNING: can't read parametric motion" << LL_ENDL; - return false; - } - - addKeyframeMotion(strA, gAnimLibrary.stringToAnimState(std::string(strA)), strB, floatA); - if (isFirstMotion) - { - isFirstMotion = false; - setDefaultKeyframeMotion(strA); - } - - p = strstr(p, "\n"); - if (!p) - { - break; - } - - p++; - num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */ - } - - return true; -} - -// End diff --git a/indra/llcharacter/llkeyframemotionparam.h b/indra/llcharacter/llkeyframemotionparam.h deleted file mode 100644 index 8c57766e9b7..00000000000 --- a/indra/llcharacter/llkeyframemotionparam.h +++ /dev/null @@ -1,169 +0,0 @@ -/** - * @file llkeyframemotionparam.h - * @brief Implementation of LLKeframeMotionParam class. - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLKEYFRAMEMOTIONPARAM_H -#define LL_LLKEYFRAMEMOTIONPARAM_H - -//----------------------------------------------------------------------------- -// Header files -//----------------------------------------------------------------------------- - -#include - -#include "llmotion.h" -#include "lljointstate.h" -#include "v3math.h" -#include "llquaternion.h" -#include "llkeyframemotion.h" - -//----------------------------------------------------------------------------- -// class LLKeyframeMotionParam -//----------------------------------------------------------------------------- -class LLKeyframeMotionParam : - public LLMotion -{ -public: - // Constructor - LLKeyframeMotionParam(const LLUUID &id); - - // Destructor - virtual ~LLKeyframeMotionParam(); - -public: - //------------------------------------------------------------------------- - // functions to support MotionController and MotionRegistry - //------------------------------------------------------------------------- - - // static constructor - // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLKeyframeMotionParam(id); } - -public: - //------------------------------------------------------------------------- - // animation callbacks to be implemented by subclasses - //------------------------------------------------------------------------- - - // motions must specify whether or not they loop - virtual bool getLoop() { - return true; - } - - // motions must report their total duration - virtual F32 getDuration() { - return mDuration; - } - - // motions must report their "ease in" duration - virtual F32 getEaseInDuration() { - return mEaseInDuration; - } - - // motions must report their "ease out" duration. - virtual F32 getEaseOutDuration() { - return mEaseOutDuration; - } - - // motions must report their priority - virtual LLJoint::JointPriority getPriority() { - return mPriority; - } - - virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } - - // called to determine when a motion should be activated/deactivated based on avatar pixel coverage - virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; } - - // run-time (post constructor) initialization, - // called after parameters have been set - // must return true to indicate success and be available for activation - virtual LLMotionInitStatus onInitialize(LLCharacter *character); - - // called when a motion is activated - // must return true to indicate success, or else - // it will be deactivated - virtual bool onActivate(); - - // called per time step - // must return true while it is active, and - // must return false when the motion is completed. - virtual bool onUpdate(F32 time, U8* joint_mask); - - // called when a motion is deactivated - virtual void onDeactivate(); - - virtual LLPose* getPose() { return mPoseBlender.getBlendedPose();} - -protected: - //------------------------------------------------------------------------- - // new functions defined by this subclass - //------------------------------------------------------------------------- - struct ParameterizedMotion - { - ParameterizedMotion(LLMotion* motion, F32 param) : mMotion(motion), mParam(param) {} - LLMotion* mMotion; - F32 mParam; - }; - - // add a motion and associated parameter triplet - bool addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value); - - // set default motion for LOD and retrieving blend constants - void setDefaultKeyframeMotion(char *); - - bool loadMotions(); - -protected: - //------------------------------------------------------------------------- - // Member Data - //------------------------------------------------------------------------- - - struct compare_motions - { - bool operator() (const ParameterizedMotion& a, const ParameterizedMotion& b) const - { - if (a.mParam != b.mParam) - return (a.mParam < b.mParam); - else - return a.mMotion < b.mMotion; - } - }; - - typedef std::set < ParameterizedMotion, compare_motions > motion_list_t; - typedef std::map motion_map_t; - motion_map_t mParameterizedMotions; - LLMotion* mDefaultKeyframeMotion; - LLCharacter* mCharacter; - LLPoseBlender mPoseBlender; - - F32 mEaseInDuration; - F32 mEaseOutDuration; - F32 mDuration; - LLJoint::JointPriority mPriority; - - LLUUID mTransactionID; -}; - -#endif // LL_LLKEYFRAMEMOTIONPARAM_H diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 0c262bf24aa..c2cb174821d 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -37,7 +37,6 @@ #include "llmotion.h" #include "llpose.h" #include "llframetimer.h" -#include "llstatemachine.h" #include "llstring.h" //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llstatemachine.cpp b/indra/llcharacter/llstatemachine.cpp deleted file mode 100644 index 38e9ef444c1..00000000000 --- a/indra/llcharacter/llstatemachine.cpp +++ /dev/null @@ -1,384 +0,0 @@ -/** - * @file llstatemachine.cpp - * @brief LLStateMachine implementation file. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llstatemachine.h" -#include "llapr.h" - -#define FSM_PRINT_STATE_TRANSITIONS (0) - -U32 LLUniqueID::sNextID = 0; - -bool operator==(const LLUniqueID &a, const LLUniqueID &b) -{ - return (a.mId == b.mId); -} - -bool operator!=(const LLUniqueID &a, const LLUniqueID &b) -{ - return (a.mId != b.mId); -} - -//----------------------------------------------------------------------------- -// LLStateDiagram -//----------------------------------------------------------------------------- -LLStateDiagram::LLStateDiagram() -{ - mDefaultState = NULL; - mUseDefaultState = false; -} - -LLStateDiagram::~LLStateDiagram() -{ - -} - -// add a state to the state graph -bool LLStateDiagram::addState(LLFSMState *state) -{ - mStates[state] = Transitions(); - return true; -} - -// add a directed transition between 2 states -bool LLStateDiagram::addTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition) -{ - StateMap::iterator state_it; - state_it = mStates.find(&start_state); - Transitions* state_transitions = NULL; - if (state_it == mStates.end() ) - { - addState(&start_state); - state_transitions = &mStates[&start_state]; - } - else - { - state_transitions = &state_it->second; - } - state_it = mStates.find(&end_state); - if (state_it == mStates.end() ) - { - addState(&end_state); - } - - Transitions::iterator transition_it = state_transitions->find(&transition); - if (transition_it != state_transitions->end()) - { - LL_ERRS() << "LLStateTable::addDirectedTransition() : transition already exists" << LL_ENDL; - return false; // transition already exists - } - - (*state_transitions)[&transition] = &end_state; - return true; -} - -// add an undirected transition between 2 states -bool LLStateDiagram::addUndirectedTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition) -{ - bool result; - result = addTransition(start_state, end_state, transition); - if (result) - { - result = addTransition(end_state, start_state, transition); - } - return result; -} - -// add a transition that exists for every state -void LLStateDiagram::addDefaultTransition(LLFSMState& end_state, LLFSMTransition& transition) -{ - mDefaultTransitions[&transition] = &end_state; -} - -// process a possible transition, and get the resulting state -LLFSMState* LLStateDiagram::processTransition(LLFSMState& start_state, LLFSMTransition& transition) -{ - // look up transition - //LLFSMState** dest_state = (mStates.getValue(&start_state))->getValue(&transition); - LLFSMState* dest_state = NULL; - StateMap::iterator state_it = mStates.find(&start_state); - if (state_it == mStates.end()) - { - return NULL; - } - Transitions::iterator transition_it = state_it->second.find(&transition); - - // try default transitions if state-specific transition not found - if (transition_it == state_it->second.end()) - { - dest_state = mDefaultTransitions[&transition]; - } - else - { - dest_state = transition_it->second; - } - - // if we have a destination state... - if (NULL != dest_state) - { - // ...return it... - return dest_state; - } - // ... otherwise ... - else - { - // ...look for default state... - if (mUseDefaultState) - { - // ...return it if we have it... - return mDefaultState; - } - else - { - // ...or else we're still in the same state. - return &start_state; - } - } -} - -void LLStateDiagram::setDefaultState(LLFSMState& default_state) -{ - mUseDefaultState = true; - mDefaultState = &default_state; -} - -S32 LLStateDiagram::numDeadendStates() -{ - S32 numDeadends = 0; - for (StateMap::value_type& state_pair : mStates) - { - if (state_pair.second.size() == 0) - { - numDeadends++; - } - } - return numDeadends; -} - -bool LLStateDiagram::stateIsValid(LLFSMState& state) -{ - if (mStates.find(&state) != mStates.end()) - { - return true; - } - return false; -} - -LLFSMState* LLStateDiagram::getState(U32 state_id) -{ - for (StateMap::value_type& state_pair : mStates) - { - if (state_pair.first->getID() == state_id) - { - return state_pair.first; - } - } - return NULL; -} - -bool LLStateDiagram::saveDotFile(const std::string& filename) -{ - LLAPRFile outfile ; - outfile.open(filename, LL_APR_W); - apr_file_t* dot_file = outfile.getFileHandle() ; - - if (!dot_file) - { - LL_WARNS() << "LLStateDiagram::saveDotFile() : Couldn't open " << filename << " to save state diagram." << LL_ENDL; - return false; - } - apr_file_printf(dot_file, "digraph StateMachine {\n\tsize=\"100,100\";\n\tfontsize=40;\n\tlabel=\"Finite State Machine\";\n\torientation=landscape\n\tratio=.77\n"); - - for (StateMap::value_type& state_pair : mStates) - { - apr_file_printf(dot_file, "\t\"%s\" [fontsize=28,shape=box]\n", state_pair.first->getName().c_str()); - } - apr_file_printf(dot_file, "\t\"All States\" [fontsize=30,style=bold,shape=box]\n"); - - for (Transitions::value_type& transition_pair : mDefaultTransitions) - { - apr_file_printf(dot_file, "\t\"All States\" -> \"%s\" [label = \"%s\",fontsize=24];\n", transition_pair.second->getName().c_str(), - transition_pair.second->getName().c_str()); - } - - if (mDefaultState) - { - apr_file_printf(dot_file, "\t\"All States\" -> \"%s\";\n", mDefaultState->getName().c_str()); - } - - - for (StateMap::value_type& state_pair : mStates) - { - LLFSMState *state = state_pair.first; - - for (Transitions::value_type& transition_pair : state_pair.second) - { - std::string state_name = state->getName(); - std::string target_name = transition_pair.second->getName(); - std::string transition_name = transition_pair.first->getName(); - apr_file_printf(dot_file, "\t\"%s\" -> \"%s\" [label = \"%s\",fontsize=24];\n", state->getName().c_str(), - target_name.c_str(), - transition_name.c_str()); - } - } - - apr_file_printf(dot_file, "}\n"); - - return true; -} - -std::ostream& operator<<(std::ostream &s, LLStateDiagram &FSM) -{ - if (FSM.mDefaultState) - { - s << "Default State: " << FSM.mDefaultState->getName() << "\n"; - } - - for (LLStateDiagram::Transitions::value_type& transition_pair : FSM.mDefaultTransitions) - { - s << "Any State -- " << transition_pair.first->getName() - << " --> " << transition_pair.second->getName() << "\n"; - } - - for (LLStateDiagram::StateMap::value_type& state_pair : FSM.mStates) - { - for (LLStateDiagram::Transitions::value_type& transition_pair : state_pair.second) - { - s << state_pair.first->getName() << " -- " << transition_pair.first->getName() - << " --> " << transition_pair.second->getName() << "\n"; - } - s << "\n"; - } - - return s; -} - -//----------------------------------------------------------------------------- -// LLStateMachine -//----------------------------------------------------------------------------- - -LLStateMachine::LLStateMachine() -{ - // we haven't received a starting state yet - mCurrentState = NULL; - mLastState = NULL; - mLastTransition = NULL; - mStateDiagram = NULL; -} - -LLStateMachine::~LLStateMachine() -{ - -} - -// returns current state -LLFSMState* LLStateMachine::getCurrentState() const -{ - return mCurrentState; -} - -// executes current state -void LLStateMachine::runCurrentState(void *data) -{ - mCurrentState->execute(data); -} - -// set current state -bool LLStateMachine::setCurrentState(LLFSMState *initial_state, void* user_data, bool skip_entry) -{ - llassert(mStateDiagram); - - if (mStateDiagram->stateIsValid(*initial_state)) - { - mLastState = mCurrentState = initial_state; - if (!skip_entry) - { - initial_state->onEntry(user_data); - } - return true; - } - - return false; -} - -bool LLStateMachine::setCurrentState(U32 state_id, void* user_data, bool skip_entry) -{ - llassert(mStateDiagram); - - LLFSMState* state = mStateDiagram->getState(state_id); - - if (state) - { - mLastState = mCurrentState = state; - if (!skip_entry) - { - state->onEntry(user_data); - } - return true; - } - - return false; -} - -void LLStateMachine::processTransition(LLFSMTransition& transition, void* user_data) -{ - llassert(mStateDiagram); - - if (NULL == mCurrentState) - { - LL_WARNS() << "mCurrentState == NULL; aborting processTransition()" << LL_ENDL; - return; - } - - LLFSMState* new_state = mStateDiagram->processTransition(*mCurrentState, transition); - - if (NULL == new_state) - { - LL_WARNS() << "new_state == NULL; aborting processTransition()" << LL_ENDL; - return; - } - - mLastTransition = &transition; - mLastState = mCurrentState; - - if (*mCurrentState != *new_state) - { - mCurrentState->onExit(user_data); - mCurrentState = new_state; - mCurrentState->onEntry(user_data); -#if FSM_PRINT_STATE_TRANSITIONS - LL_INFOS() << "Entering state " << mCurrentState->getName() << - " on transition " << transition.getName() << " from state " << - mLastState->getName() << LL_ENDL; -#endif - } -} - -void LLStateMachine::setStateDiagram(LLStateDiagram* diagram) -{ - mStateDiagram = diagram; -} diff --git a/indra/llcharacter/llstatemachine.h b/indra/llcharacter/llstatemachine.h deleted file mode 100644 index 9a33798d963..00000000000 --- a/indra/llcharacter/llstatemachine.h +++ /dev/null @@ -1,147 +0,0 @@ -/** - * @file llstatemachine.h - * @brief LLStateMachine class header file. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLSTATEMACHINE_H -#define LL_LLSTATEMACHINE_H - -#include - -#include "llerror.h" -#include - -class LLUniqueID -{ - friend bool operator==(const LLUniqueID &a, const LLUniqueID &b); - friend bool operator!=(const LLUniqueID &a, const LLUniqueID &b); -protected: - static U32 sNextID; - U32 mId; -public: - LLUniqueID(){mId = sNextID++;} - virtual ~LLUniqueID(){} - U32 getID() {return mId;} -}; - -class LLFSMTransition : public LLUniqueID -{ -public: - LLFSMTransition() : LLUniqueID(){}; - virtual std::string getName()const { return "unnamed"; } -}; - -class LLFSMState : public LLUniqueID -{ -public: - LLFSMState() : LLUniqueID(){}; - virtual void onEntry(void *){}; - virtual void onExit(void *){}; - virtual void execute(void *){}; - virtual std::string getName() const { return "unnamed"; } -}; - -class LLStateDiagram -{ -typedef std::map Transitions; - -friend std::ostream& operator<<(std::ostream &s, LLStateDiagram &FSM); -friend class LLStateMachine; - -protected: - typedef std::map StateMap; - StateMap mStates; - Transitions mDefaultTransitions; - LLFSMState* mDefaultState; - bool mUseDefaultState; - -public: - LLStateDiagram(); - virtual ~LLStateDiagram(); - -protected: - // add a state to the state graph, executed implicitly when adding transitions - bool addState(LLFSMState *state); - - // add a directed transition between 2 states - bool addTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition); - - // add an undirected transition between 2 states - bool addUndirectedTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition); - - // add a transition that is taken if none other exist - void addDefaultTransition(LLFSMState& end_state, LLFSMTransition& transition); - - // process a possible transition, and get the resulting state - LLFSMState* processTransition(LLFSMState& start_state, LLFSMTransition& transition); - - // add a transition that exists for every state - void setDefaultState(LLFSMState& default_state); - - // return total number of states with no outgoing transitions - S32 numDeadendStates(); - - // does this state exist in the state diagram? - bool stateIsValid(LLFSMState& state); - - // get a state pointer by ID - LLFSMState* getState(U32 state_id); - -public: - // save the graph in a DOT file for rendering and visualization - bool saveDotFile(const std::string& filename); -}; - -class LLStateMachine -{ -protected: - LLFSMState* mCurrentState; - LLFSMState* mLastState; - LLFSMTransition* mLastTransition; - LLStateDiagram* mStateDiagram; - -public: - LLStateMachine(); - virtual ~LLStateMachine(); - - // set state diagram - void setStateDiagram(LLStateDiagram* diagram); - - // process this transition - void processTransition(LLFSMTransition &transition, void* user_data); - - // returns current state - LLFSMState* getCurrentState() const; - - // execute current state - void runCurrentState(void *data); - - // set state by state pointer - bool setCurrentState(LLFSMState *initial_state, void* user_data, bool skip_entry = true); - - // set state by unique ID - bool setCurrentState(U32 state_id, void* user_data, bool skip_entry = true); -}; - -#endif //_LL_LLSTATEMACHINE_H diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 4d04c2c1190..32226a62e6c 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -68,6 +68,7 @@ set(llcommon_SOURCE_FILES llmetricperformancetester.cpp llmortician.cpp llmutex.cpp + llpointer.cpp llptrto.cpp llpredicate.cpp llprocess.cpp diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index a0394da2816..404e0c71cea 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -163,6 +163,28 @@ constexpr U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only constexpr U8 SIM_ACCESS_DOWN = 254; constexpr U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; +// map item types +constexpr U32 MAP_ITEM_TELEHUB = 0x01; +constexpr U32 MAP_ITEM_PG_EVENT = 0x02; +constexpr U32 MAP_ITEM_MATURE_EVENT = 0x03; +// constexpr U32 MAP_ITEM_POPULAR = 0x04; // No longer supported, 2009-03-02 KLW +// constexpr U32 MAP_ITEM_AGENT_COUNT = 0x05; +constexpr U32 MAP_ITEM_AGENT_LOCATIONS = 0x06; +constexpr U32 MAP_ITEM_LAND_FOR_SALE = 0x07; +constexpr U32 MAP_ITEM_CLASSIFIED = 0x08; +constexpr U32 MAP_ITEM_ADULT_EVENT = 0x09; +constexpr U32 MAP_ITEM_LAND_FOR_SALE_ADULT = 0x0a; + +// Region map layer numbers +constexpr S32 MAP_SIM_OBJECTS = 0; +constexpr S32 MAP_SIM_TERRAIN = 1; +constexpr S32 MAP_SIM_LAND_FOR_SALE = 2; // Transparent alpha overlay of land for sale +constexpr S32 MAP_SIM_IMAGE_TYPES = 3; // Number of map layers +constexpr S32 MAP_SIM_INFO_MASK = 0x00FFFFFF; // Agent access may be stuffed into upper byte +constexpr S32 MAP_SIM_LAYER_MASK = 0x0000FFFF; // Layer info is in lower 16 bits +constexpr S32 MAP_SIM_RETURN_NULL_SIMS = 0x00010000; +constexpr S32 MAP_SIM_PRELUDE = 0x00020000; + // attachment constants constexpr U8 ATTACHMENT_ADD = 0x80; diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index c532620daa1..f92bb98ba6b 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -93,6 +93,7 @@ bool LLApp::sDisableCrashlogger = false; LLScalarCond LLApp::sStatus{LLApp::APP_STATUS_STOPPED}; LLAppErrorHandler LLApp::sErrorHandler = NULL; +bool gDisconnected = false; LLApp::LLApp() { diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index 57f5a112d9b..fef7dc80b3c 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -50,6 +50,8 @@ void clear_signals(); #endif +extern bool gDisconnected; + class LL_COMMON_API LLApp { public: @@ -283,6 +285,7 @@ class LL_COMMON_API LLApp #ifdef LL_WINDOWS virtual bool reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { return false; } + virtual bool reportCustomToBugsplat(const std::string& desription) { return false; } #endif public: diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 5205699b92c..5545bb71af4 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -41,6 +41,9 @@ #include "llstring.h" #include "llfasttimer.h" +#include +#include + static const F64 LL_APR_USEC_PER_SEC = 1000000.0; // should be APR_USEC_PER_SEC, but that relies on INT64_C which // isn't defined in glib under our build set up for some reason @@ -64,7 +67,7 @@ std::string LLDate::asString() const { std::ostringstream stream; toStream(stream); - return stream.str(); + return std::move(stream).str(); } //@ brief Converts time in seconds since EPOCH @@ -184,7 +187,7 @@ bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *se bool LLDate::fromString(const std::string& iso8601_date) { - std::istringstream stream(iso8601_date); + boost::iostreams::stream stream(iso8601_date.data(), iso8601_date.size()); return fromStream(stream); } diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index b14464382b7..6f5e57c3de1 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -480,7 +480,7 @@ namespace } - typedef std::map LevelMap; + typedef std::unordered_map LevelMap; typedef std::vector Recorders; typedef std::vector CallSiteVector; @@ -501,7 +501,7 @@ namespace LevelMap mClassLevelMap; LevelMap mFileLevelMap; LevelMap mTagLevelMap; - std::map mUniqueLogMessages; + std::unordered_map mUniqueLogMessages; LLError::FatalFunction mCrashFunction; LLError::TimeFunction mTimeFunction; @@ -1404,7 +1404,7 @@ namespace LLError { std::ostringstream message_stream; - std::map::iterator messageIter = s->mUniqueLogMessages.find(message); + auto messageIter = s->mUniqueLogMessages.find(message); if (messageIter != s->mUniqueLogMessages.end()) { messageIter->second++; diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index d254fa54074..3c58d1df227 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -70,7 +70,6 @@ namespace LLError Setting a level means log messages at that level or above. */ - LL_COMMON_API void setPrintLocation(bool); LL_COMMON_API void setDefaultLevel(LLError::ELevel); LL_COMMON_API ELevel getDefaultLevel(); LL_COMMON_API void setAlwaysFlush(bool flush); diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index a539e4fe282..f752e315632 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -187,13 +187,34 @@ static unsigned short get_fileattr(const std::wstring& utf16path, bool dontFollo CloseHandle(file_handle); return st_mode; } + // Retrieve last error before calling CloseHandle() + DWORD last_error = GetLastError(); + CloseHandle(file_handle); + set_errno_from_oserror(last_error); + } + else + { + set_errno_from_oserror(GetLastError()); } - // Retrieve last error and set errno before calling CloseHandle() - set_errno_from_oserror(GetLastError()); - if (file_handle != INVALID_HANDLE_VALUE) + // If CreateFileW approach failed (e.g., exFAT), try the simpler GetFileAttributesW() + // GetFileAttributesW() always follows symlinks, so we skip this fallback when dontFollowSymLink is true. + if (!dontFollowSymLink) { - CloseHandle(file_handle); + DWORD attributes = GetFileAttributesW(utf16path.c_str()); + if (attributes != INVALID_FILE_ATTRIBUTES) + { + bool is_directory = (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + unsigned short st_mode = is_directory ? S_IFDIR : S_IFREG; + st_mode |= (attributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD | S_IWRITE; + + // propagate user bits to group/other fields: + st_mode |= (st_mode & 0700) >> 3; + st_mode |= (st_mode & 0700) >> 6; + + return st_mode; + } + set_errno_from_oserror(GetLastError()); } return 0; } diff --git a/indra/llcommon/llheteromap.cpp b/indra/llcommon/llheteromap.cpp index 823bea7a3c1..03dd7856b60 100644 --- a/indra/llcommon/llheteromap.cpp +++ b/indra/llcommon/llheteromap.cpp @@ -27,6 +27,6 @@ LLHeteroMap::~LLHeteroMap() // pair.second is the std::pair; pair.second.first is the void*; // pair.second.second points to the deleter function (pair.second.second)(pair.second.first); - pair.second.first = NULL; + pair.second.first = nullptr; } } diff --git a/indra/llcommon/llheteromap.h b/indra/llcommon/llheteromap.h index d8e6fefb17e..211dfaae834 100644 --- a/indra/llcommon/llheteromap.h +++ b/indra/llcommon/llheteromap.h @@ -12,9 +12,10 @@ #if ! defined(LL_LLHETEROMAP_H) #define LL_LLHETEROMAP_H +#include #include #include // std::pair -#include +#include /** * LLHeteroMap addresses an odd requirement. Usually when you want to put @@ -43,7 +44,7 @@ class LLHeteroMap // Look up map entry by typeid(T). We don't simply use mMap[typeid(T)] // because that requires default-constructing T on every lookup. For // some kinds of T, that could be expensive. - TypeMap::iterator found = mMap.find(&typeid(T)); + TypeMap::iterator found = mMap.find(typeid(T)); if (found == mMap.end()) { // Didn't find typeid(T). Create an entry. Because we're storing @@ -52,8 +53,8 @@ class LLHeteroMap void* ptr = new T(); void (*dlfn)(void*) = &deleter; std::pair inserted = - mMap.insert(TypeMap::value_type(&typeid(T), - TypeMap::mapped_type(ptr, dlfn))); + mMap.emplace(typeid(T), + TypeMap::mapped_type(ptr, dlfn)); // Okay, now that we have an entry, claim we found it. found = inserted.first; } @@ -71,23 +72,9 @@ class LLHeteroMap delete static_cast(p); } - // Comparing two std::type_info* values is tricky, because the standard - // does not guarantee that there will be only one type_info instance for a - // given type. In other words, &typeid(A) in one part of the program may - // not always equal &typeid(A) in some other part. Use special comparator. - struct type_info_ptr_comp - { - bool operator()(const std::type_info* lhs, const std::type_info* rhs) const - { - return lhs->before(*rhs); - } - }; - - // What we actually store is a map from std::type_info (permitting lookup + // What we actually store is a map from std::type_index (permitting lookup // by object type) to a void* pointer to the object PLUS its deleter. - typedef std::map< - const std::type_info*, std::pair, - type_info_ptr_comp> + typedef std::unordered_map> TypeMap; TypeMap mMap; }; diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index b01ea0bfb1b..b220afadfca 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -34,7 +34,6 @@ #include #include #include -#include #include "llerror.h" #include "llstl.h" @@ -267,7 +266,7 @@ namespace LLInitParam private: struct Inaccessable{}; public: - typedef std::map value_name_map_t; + typedef std::unordered_map value_name_map_t; typedef Inaccessable name_t; typedef TypeValues type_value_t; typedef ParamValue::value_t> param_value_t; @@ -294,7 +293,7 @@ namespace LLInitParam static std::vector* getPossibleValues() { - return NULL; + return nullptr; } void assignNamedValue(const Inaccessable& name) @@ -310,7 +309,7 @@ namespace LLInitParam return param_value_t::getValue(); } - static value_name_map_t* getValueNames() {return NULL;} + static value_name_map_t* getValueNames() { return nullptr; } }; // helper class to implement name value lookups @@ -321,7 +320,7 @@ namespace LLInitParam { typedef TypeValuesHelper self_t; public: - typedef typename std::map value_name_map_t; + typedef typename std::unordered_map value_name_map_t; typedef std::string name_t; typedef self_t type_value_t; typedef ParamValue::value_t> param_value_t; @@ -497,9 +496,9 @@ namespace LLInitParam typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&); typedef std::function parser_inspect_func_t; - typedef std::map parser_read_func_map_t; - typedef std::map parser_write_func_map_t; - typedef std::map parser_inspect_func_map_t; + typedef std::unordered_map parser_read_func_map_t; + typedef std::unordered_map parser_write_func_map_t; + typedef std::unordered_map parser_inspect_func_map_t; public: @@ -514,7 +513,7 @@ namespace LLInitParam template bool readValue(T& param, typename std::enable_if_t>* dummy = 0) { - parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); + parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(typeid(T)); if (found_it != mParserReadFuncs->end()) { return found_it->second(*this, (void*)¶m); @@ -525,14 +524,14 @@ namespace LLInitParam template bool readValue(T& param, typename std::enable_if_t >* dummy = 0) { - parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); + parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(typeid(T)); if (found_it != mParserReadFuncs->end()) { return found_it->second(*this, (void*)¶m); } else { - found_it = mParserReadFuncs->find(&typeid(S32)); + found_it = mParserReadFuncs->find(typeid(S32)); if (found_it != mParserReadFuncs->end()) { S32 int_value; @@ -546,7 +545,7 @@ namespace LLInitParam template bool writeValue(const T& param, name_stack_t& name_stack) { - parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T)); + parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(typeid(T)); if (found_it != mParserWriteFuncs->end()) { return found_it->second(*this, (const void*)¶m, name_stack); @@ -557,7 +556,7 @@ namespace LLInitParam // dispatch inspection to registered inspection functions, for each parameter in a param block template bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values) { - parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T)); + parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(typeid(T)); if (found_it != mParserInspectFuncs->end()) { found_it->second(name_stack, min_count, max_count, possible_values); @@ -574,16 +573,16 @@ namespace LLInitParam protected: template - void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL) + void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = nullptr) { - mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func)); - mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func)); + mParserReadFuncs->emplace(typeid(T), read_func); + mParserWriteFuncs->emplace(typeid(T), write_func); } template void registerInspectFunc(parser_inspect_func_t inspect_func) { - mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func)); + mParserInspectFuncs->emplace(typeid(T), inspect_func); } bool mParseSilently; @@ -614,7 +613,7 @@ namespace LLInitParam { struct UserData { - virtual ~UserData() {} + virtual ~UserData() = default; }; typedef bool(*merge_func_t)(Param&, const Param&, bool); @@ -665,7 +664,7 @@ namespace LLInitParam void aggregateBlockData(BlockDescriptor& src_block_data); void addParam(ParamDescriptorPtr param, const char* name); - typedef boost::unordered_map param_map_t; + typedef std::unordered_map> param_map_t; typedef std::vector param_list_t; typedef std::list all_params_list_t; typedef std::vector > param_validation_list_t; @@ -679,38 +678,26 @@ namespace LLInitParam class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed }; - //TODO: implement in terms of owned_ptr - template + // TODO: implement in terms of owned_ptr + template class LazyValue - { - public: - LazyValue() - : mPtr(NULL) - {} + { + public: + LazyValue() = default; - ~LazyValue() - { - delete mPtr; - } + ~LazyValue() { delete mPtr; } - LazyValue(const T& value) - { - mPtr = new T(value); - } + LazyValue(const T& value) { mPtr = new T(value); } - LazyValue(const LazyValue& other) - : mPtr(NULL) - { - *this = other; - } + LazyValue(const LazyValue& other) : mPtr(nullptr) { *this = other; } - LazyValue& operator = (const LazyValue& other) - { + LazyValue& operator=(const LazyValue& other) + { if (!other.mPtr) { delete mPtr; - mPtr = NULL; - } + mPtr = nullptr; + } else { if (!mPtr) @@ -721,23 +708,21 @@ namespace LLInitParam { *mPtr = *(other.mPtr); } - } - return *this; } + return *this; + } bool operator==(const LazyValue& other) const { - if (empty() || other.empty()) return false; + if (empty() || other.empty()) + return false; return *mPtr == *other.mPtr; } - bool empty() const - { - return mPtr == NULL; - } + bool empty() const { return mPtr == nullptr; } - void set(const T& other) - { + void set(const T& other) + { if (!mPtr) { mPtr = new T(other); @@ -748,36 +733,26 @@ namespace LLInitParam } } - const T& get() const - { - return *ensureInstance(); - } + const T& get() const { return *ensureInstance(); } - T& get() - { - return *ensureInstance(); - } + T& get() { return *ensureInstance(); } - operator const T&() const - { - return get(); - } + operator const T&() const { return get(); } - private: - // lazily allocate an instance of T - T* ensureInstance() const + private: + // lazily allocate an instance of T + T* ensureInstance() const + { + if (mPtr == nullptr) { - if (mPtr == NULL) - { - mPtr = new T(); - } - return mPtr; + mPtr = new T(); } + return mPtr; + } - private: - - mutable T* mPtr; - }; + private: + mutable T* mPtr = nullptr; + }; // root class of all parameter blocks @@ -864,7 +839,7 @@ namespace LLInitParam mParamProvided(false) {} - virtual ~BaseBlock() {} + virtual ~BaseBlock() = default; bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false); param_handle_t getHandleFromParam(const Param* param) const; diff --git a/indra/newview/llfloatersounddevices.h b/indra/llcommon/llpointer.cpp old mode 100644 new mode 100755 similarity index 55% rename from indra/newview/llfloatersounddevices.h rename to indra/llcommon/llpointer.cpp index 9b21b62747a..1bb7055b3a5 --- a/indra/newview/llfloatersounddevices.h +++ b/indra/llcommon/llpointer.cpp @@ -1,11 +1,12 @@ /** - * @file llfloatersounddevices.h - * @author Leyla Farazha - * @brief Sound Preferences used for minimal skin + * @file llpointer.cpp + * @author Nat Goodspeed + * @date 2024-09-26 + * @brief Implementation for llpointer. * -* $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2024, 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 @@ -25,25 +26,18 @@ * $/LicenseInfo$ */ -#ifndef LL_LLFLOATERSOUNDDEVICES_H -#define LL_LLFLOATERSOUNDDEVICES_H - -#include "lltransientdockablefloater.h" - -class LLFloaterSoundDevices : public LLTransientDockableFloater +// Precompiled header +#include "linden_common.h" +// associated header +#include "llpointer.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "llerror.h" + +void LLPointerBase::wild_dtor(std::string_view msg) { -public: - - LOG_CLASS(LLFloaterSoundDevices); - - LLFloaterSoundDevices(const LLSD& key); - ~LLFloaterSoundDevices(); - - bool postBuild() override; - void setDocked(bool docked, bool pop_on_undock = true) override; - void setFocus(bool b) override; -}; - - -#endif //LL_LLFLOATERSOUNDDEVICES_H - +// LL_WARNS() << msg << LL_ENDL; + llassert_msg(false, msg); +} diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 048547e4ccb..d2dcf530e50 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -26,8 +26,9 @@ #ifndef LLPOINTER_H #define LLPOINTER_H -#include "llerror.h" // *TODO: consider eliminating this -#include "llmutex.h" +#include +#include +#include // std::swap() //---------------------------------------------------------------------------- // RefCount objects should generally only be accessed by way of LLPointer<>'s @@ -42,8 +43,18 @@ //---------------------------------------------------------------------------- +class LLPointerBase +{ +protected: + // alert the coder that a referenced type's destructor did something very + // strange -- this is in a non-template base class so we can hide the + // implementation in llpointer.cpp + static void wild_dtor(std::string_view msg); +}; + // Note: relies on Type having ref() and unref() methods -template class LLPointer +template +class LLPointer: public LLPointerBase { public: template @@ -60,6 +71,13 @@ template class LLPointer ref(); } + // Even though the template constructors below accepting + // (const LLPointer&) and (LLPointer&&) appear to + // subsume these specific (const LLPointer&) and (LLPointer&&) + // constructors, the compiler recognizes these as The Copy Constructor and + // The Move Constructor, respectively. In other words, even in the + // presence of the LLPointer constructors, we still must specify + // the LLPointer constructors. LLPointer(const LLPointer& ptr) : mPointer(ptr.mPointer) { @@ -98,39 +116,52 @@ template class LLPointer const Type& operator*() const { return *mPointer; } Type& operator*() { return *mPointer; } - operator BOOL() const { return (mPointer != nullptr); } operator bool() const { return (mPointer != nullptr); } bool operator!() const { return (mPointer == nullptr); } bool isNull() const { return (mPointer == nullptr); } bool notNull() const { return (mPointer != nullptr); } operator Type*() const { return mPointer; } - bool operator !=(Type* ptr) const { return (mPointer != ptr); } - bool operator ==(Type* ptr) const { return (mPointer == ptr); } - bool operator ==(const LLPointer& ptr) const { return (mPointer == ptr.mPointer); } - bool operator < (const LLPointer& ptr) const { return (mPointer < ptr.mPointer); } - bool operator > (const LLPointer& ptr) const { return (mPointer > ptr.mPointer); } + template + bool operator !=(Type1* ptr) const { return (mPointer != ptr); } + template + bool operator ==(Type1* ptr) const { return (mPointer == ptr); } + template + bool operator !=(const LLPointer& ptr) const { return (mPointer != ptr.mPointer); } + template + bool operator ==(const LLPointer& ptr) const { return (mPointer == ptr.mPointer); } + bool operator < (const LLPointer& ptr) const { return (mPointer < ptr.mPointer); } + bool operator > (const LLPointer& ptr) const { return (mPointer > ptr.mPointer); } LLPointer& operator =(Type* ptr) { - assign(ptr); + // copy-and-swap idiom, see http://gotw.ca/gotw/059.htm + LLPointer temp(ptr); + using std::swap; // per Swappable convention + swap(*this, temp); return *this; } + // Even though the template assignment operators below accepting + // (const LLPointer&) and (LLPointer&&) appear to + // subsume these specific (const LLPointer&) and (LLPointer&&) + // assignment operators, the compiler recognizes these as Copy Assignment + // and Move Assignment, respectively. In other words, even in the presence + // of the LLPointer assignment operators, we still must specify + // the LLPointer operators. LLPointer& operator =(const LLPointer& ptr) { - assign(ptr); + LLPointer temp(ptr); + using std::swap; // per Swappable convention + swap(*this, temp); return *this; } LLPointer& operator =(LLPointer&& ptr) { - if (mPointer != ptr.mPointer) - { - unref(); - mPointer = ptr.mPointer; - ptr.mPointer = nullptr; - } + LLPointer temp(std::move(ptr)); + using std::swap; // per Swappable convention + swap(*this, temp); return *this; } @@ -138,28 +169,32 @@ template class LLPointer template LLPointer& operator =(const LLPointer& ptr) { - assign(ptr.get()); + LLPointer temp(ptr); + using std::swap; // per Swappable convention + swap(*this, temp); return *this; } template LLPointer& operator =(LLPointer&& ptr) { - if (mPointer != ptr.mPointer) - { - unref(); - mPointer = ptr.mPointer; - ptr.mPointer = nullptr; - } + LLPointer temp(std::move(ptr)); + using std::swap; // per Swappable convention + swap(*this, temp); return *this; } // Just exchange the pointers, which will not change the reference counts. static void swap(LLPointer& a, LLPointer& b) { - Type* temp = a.mPointer; - a.mPointer = b.mPointer; - b.mPointer = temp; + using std::swap; // per Swappable convention + swap(a.mPointer, b.mPointer); + } + + // Put swap() overload in the global namespace, per Swappable convention + friend void swap(LLPointer& a, LLPointer& b) + { + LLPointer::swap(a, b); } protected: @@ -184,191 +219,19 @@ template class LLPointer temp->unref(); if (mPointer != nullptr) { - LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; + wild_dtor("Unreference did assignment to non-NULL because of destructor"); unref(); } } } #endif // LL_LIBRARY_INCLUDE - void assign(const LLPointer& ptr) - { - if (mPointer != ptr.mPointer) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } - } - protected: Type* mPointer; }; -template class LLConstPointer -{ - template - friend class LLConstPointer; -public: - LLConstPointer() : - mPointer(nullptr) - { - } - - LLConstPointer(const Type* ptr) : - mPointer(ptr) - { - ref(); - } - - LLConstPointer(const LLConstPointer& ptr) : - mPointer(ptr.mPointer) - { - ref(); - } - - LLConstPointer(LLConstPointer&& ptr) noexcept - { - mPointer = ptr.mPointer; - ptr.mPointer = nullptr; - } - - // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLConstPointer(const LLConstPointer& ptr) : - mPointer(ptr.get()) - { - ref(); - } - - template - LLConstPointer(LLConstPointer&& ptr) noexcept : - mPointer(ptr.get()) - { - ptr.mPointer = nullptr; - } - - ~LLConstPointer() - { - unref(); - } - - const Type* get() const { return mPointer; } - const Type* operator->() const { return mPointer; } - const Type& operator*() const { return *mPointer; } - - operator BOOL() const { return (mPointer != nullptr); } - operator bool() const { return (mPointer != nullptr); } - bool operator!() const { return (mPointer == nullptr); } - bool isNull() const { return (mPointer == nullptr); } - bool notNull() const { return (mPointer != nullptr); } - - operator const Type*() const { return mPointer; } - bool operator !=(const Type* ptr) const { return (mPointer != ptr); } - bool operator ==(const Type* ptr) const { return (mPointer == ptr); } - bool operator ==(const LLConstPointer& ptr) const { return (mPointer == ptr.mPointer); } - bool operator < (const LLConstPointer& ptr) const { return (mPointer < ptr.mPointer); } - bool operator > (const LLConstPointer& ptr) const { return (mPointer > ptr.mPointer); } - - LLConstPointer& operator =(const Type* ptr) - { - if( mPointer != ptr ) - { - unref(); - mPointer = ptr; - ref(); - } - - return *this; - } - - LLConstPointer& operator =(const LLConstPointer& ptr) - { - if( mPointer != ptr.mPointer ) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } - return *this; - } - - LLConstPointer& operator =(LLConstPointer&& ptr) - { - if (mPointer != ptr.mPointer) - { - unref(); - mPointer = ptr.mPointer; - ptr.mPointer = nullptr; - } - return *this; - } - - // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLConstPointer& operator =(const LLConstPointer& ptr) - { - if( mPointer != ptr.get() ) - { - unref(); - mPointer = ptr.get(); - ref(); - } - return *this; - } - - template - LLConstPointer& operator =(LLConstPointer&& ptr) - { - if (mPointer != ptr.mPointer) - { - unref(); - mPointer = ptr.mPointer; - ptr.mPointer = nullptr; - } - return *this; - } - - // Just exchange the pointers, which will not change the reference counts. - static void swap(LLConstPointer& a, LLConstPointer& b) - { - const Type* temp = a.mPointer; - a.mPointer = b.mPointer; - b.mPointer = temp; - } - -protected: -#ifdef LL_LIBRARY_INCLUDE - void ref(); - void unref(); -#else // LL_LIBRARY_INCLUDE - void ref() - { - if (mPointer) - { - mPointer->ref(); - } - } - - void unref() - { - if (mPointer) - { - const Type *temp = mPointer; - mPointer = nullptr; - temp->unref(); - if (mPointer != nullptr) - { - LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; - unref(); - } - } - } -#endif // LL_LIBRARY_INCLUDE - -protected: - const Type* mPointer; -}; +template +using LLConstPointer = LLPointer; template class LLCopyOnWritePointer : public LLPointer @@ -418,38 +281,26 @@ class LLCopyOnWritePointer : public LLPointer bool mStayUnique; }; -template -bool operator!=(Type* lhs, const LLPointer& rhs) +template +bool operator!=(Type0* lhs, const LLPointer& rhs) { return (lhs != rhs.get()); } -template -bool operator==(Type* lhs, const LLPointer& rhs) +template +bool operator==(Type0* lhs, const LLPointer& rhs) { return (lhs == rhs.get()); } -// boost hash adapter -template -struct boost::hash> -{ - typedef LLPointer argument_type; - typedef std::size_t result_type; - result_type operator()(argument_type const& s) const - { - return (std::size_t) s.get(); - } -}; - -// Adapt boost hash to std hash +// Specialize for std::hash namespace std { template struct hash> { std::size_t operator()(LLPointer const& s) const noexcept { - return boost::hash>()(s); + return std::hash()(s.get()); } }; } diff --git a/indra/llcommon/llpounceable.h b/indra/llcommon/llpounceable.h index e86098f20bc..20561b0c658 100644 --- a/indra/llcommon/llpounceable.h +++ b/indra/llcommon/llpounceable.h @@ -38,9 +38,9 @@ #include "llsingleton.h" #include #include -#include #include +#include #include // Forward declare the user template, since we want to be able to point to it @@ -86,7 +86,7 @@ class LLPounceableQueueSingleton: // instance will call on the SAME LLPounceableQueueSingleton instance -- // given how class statics work. We must keep a separate queue for each // LLPounceable instance. Use a hash map for that. - typedef boost::unordered_map map_t; + typedef std::unordered_map map_t; public: // Disambiguate queues belonging to different LLPounceables. diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index 670b7401338..4a01ec567ec 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -176,13 +176,13 @@ 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); + const char* remainptr = static_cast(bufi->data()); std::size_t remainlen = boost::asio::buffer_size(*bufi); while (remainlen) { @@ -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)); 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. @@ -657,10 +657,7 @@ LLProcess::LLProcess(const LLSDOrParams& params): // case), e.g. by calling operator(), returns a reference to *the same // instance* of the wrapped type that's stored in our Block subclass. // That's important! We know 'params' persists throughout this method - // call; but without that guarantee, we'd have to assume that converting - // one of its members to std::string might return a different (temp) - // instance. Capturing the c_str() from a temporary std::string is Bad Bad - // Bad. But armed with this knowledge, when you see params.cwd().c_str(), + // call; but without that guarantee, when you see params.cwd().c_str(), // grit your teeth and smile and carry on. if (params.cwd.isProvided()) diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h index 35335e12130..92f8ae32452 100644 --- a/indra/llcommon/llregistry.h +++ b/indra/llcommon/llregistry.h @@ -32,21 +32,11 @@ #include "llsingleton.h" #include "llstl.h" -template -struct LLRegistryDefaultComparator -{ - bool operator()(const T& lhs, const T& rhs) const - { - using std::less; - return less()(lhs, rhs); - } -}; - -template > +template class LLRegistry { public: - typedef LLRegistry registry_t; + typedef LLRegistry registry_t; typedef const KEY& ref_const_key_t; typedef const VALUE& ref_const_value_t; typedef const VALUE* ptr_const_value_t; @@ -54,9 +44,9 @@ class LLRegistry class Registrar { - friend class LLRegistry; + friend class LLRegistry; public: - typedef std::map registry_map_t; + typedef std::map registry_map_t; bool add(ref_const_key_t key, ref_const_value_t value) { @@ -234,9 +224,9 @@ class LLRegistry Registrar mDefaultRegistrar; }; -template > +template class LLRegistrySingleton - : public LLRegistry, + : public LLRegistry, public LLSingleton { // This LLRegistrySingleton doesn't use LLSINGLETON(LLRegistrySingleton) @@ -244,7 +234,7 @@ class LLRegistrySingleton // LLRegistrySingleton. So each concrete subclass needs // LLSINGLETON(whatever) -- not this intermediate base class. public: - typedef LLRegistry registry_t; + typedef LLRegistry registry_t; typedef const KEY& ref_const_key_t; typedef const VALUE& ref_const_value_t; typedef VALUE* ptr_value_t; @@ -309,7 +299,7 @@ class LLRegistrySingleton }; // convenience functions - typedef typename LLRegistry::Registrar& ref_registrar_t; + typedef typename LLRegistry::Registrar& ref_registrar_t; static ref_registrar_t currentRegistrar() { return singleton_t::instance().registry_t::currentRegistrar(); diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 77fe545c3f0..ce39bc7af3b 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -39,6 +39,9 @@ #include +#include +#include + // Defend against a caller forcibly passing a negative number into an unsigned // size_t index param inline @@ -103,6 +106,9 @@ class LLSD::Impl U32 mUseCount; public: + static void destruct(Impl*& var); + ///< safely decrement or destroy var + static void reset(Impl*& var, Impl* impl); ///< safely set var to refer to the new impl (possibly shared) @@ -166,7 +172,7 @@ class LLSD::Impl virtual const LLSD& ref(size_t) const { return undef(); } virtual LLSD::map_const_iterator beginMap() const { return endMap(); } - virtual LLSD::map_const_iterator endMap() const { static const std::map empty; return empty.end(); } + virtual LLSD::map_const_iterator endMap() const { static const LLSD::llsd_map_t empty; return empty.end(); } virtual LLSD::array_const_iterator beginArray() const { return endArray(); } virtual LLSD::array_const_iterator endArray() const { static const std::vector empty; return empty.end(); } @@ -345,18 +351,7 @@ namespace LLSD::Real ImplString::asReal() const { - F64 v = 0.0; - std::istringstream i_stream(mValue); - i_stream >> v; - - // we would probably like to ignore all trailing whitespace as - // well, but for now, simply eat the next character, and make - // sure we reached the end of the string. - // *NOTE: gcc 2.95 does not generate an eof() event on the - // stream operation above, so we manually get here to force it - // across platforms. - int c = i_stream.get(); - return ((EOF ==c) ? v : 0.0); + return llsd::string_to_real(mValue); } @@ -431,7 +426,7 @@ namespace class ImplMap final : public LLSD::Impl { private: - typedef std::map> DataMap; + using DataMap = LLSD::llsd_map_t; DataMap mData; @@ -457,7 +452,7 @@ namespace << it.second.asXMLRPCValue() << ""; } os << ""; - return os.str(); + return std::move(os).str(); } virtual bool has(std::string_view) const; @@ -467,8 +462,13 @@ namespace using LLSD::Impl::ref; // Unhiding ref(size_t) virtual LLSD get(std::string_view) const; virtual LLSD getKeys() const; + void insert(std::string&& k, const LLSD& v); + void insert(std::string&& k, LLSD&& v); void insert(std::string_view k, const LLSD& v); + void insert(std::string_view k, LLSD&& v); virtual void erase(const LLSD::String&); + LLSD& ref(std::string&&); + virtual const LLSD& ref(std::string&&) const; LLSD& ref(std::string_view); virtual const LLSD& ref(std::string_view) const; @@ -525,18 +525,58 @@ namespace return keys; } + void ImplMap::insert(std::string&& k, const LLSD& v) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; + mData.emplace(std::move(k), v); + } + + void ImplMap::insert(std::string&& k, LLSD&& v) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; + mData.emplace(std::move(k), std::move(v)); + } + void ImplMap::insert(std::string_view k, const LLSD& v) { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; mData.emplace(k, v); } + void ImplMap::insert(std::string_view k, LLSD&& v) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; + mData.emplace(k, std::move(v)); + } + void ImplMap::erase(const LLSD::String& k) { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; mData.erase(k); } + LLSD& ImplMap::ref(std::string&& k) + { + DataMap::iterator i = mData.lower_bound(k); + if (i == mData.end() || mData.key_comp()(k, i->first)) + { + return mData.emplace_hint(i, std::make_pair(std::move(k), LLSD()))->second; + } + + return i->second; + } + + const LLSD& ImplMap::ref(std::string&& k) const + { + DataMap::const_iterator i = mData.lower_bound(k); + if (i == mData.end() || mData.key_comp()(k, i->first)) + { + return undef(); + } + + return i->second; + } + LLSD& ImplMap::ref(std::string_view k) { DataMap::iterator i = mData.lower_bound(k); @@ -598,7 +638,7 @@ namespace ImplArray(const DataVector& data) : mData(data) { } public: - ImplArray() { } + ImplArray() = default; virtual ImplArray& makeArray(Impl*&); @@ -615,7 +655,7 @@ namespace os << it.asXMLRPCValue(); } os << ""; - return os.str(); + return std::move(os).str(); } using LLSD::Impl::get; // Unhiding get(LLSD::String) @@ -625,10 +665,13 @@ namespace virtual LLSD get(size_t) const; void set(size_t, const LLSD&); void insert(size_t, const LLSD&); + void insert(size_t, LLSD&&); LLSD& append(const LLSD&); + LLSD& append(LLSD&&); virtual void erase(size_t); LLSD& ref(size_t); virtual const LLSD& ref(size_t) const; + void reserve(size_t size) { mData.reserve(size); } LLSD::array_iterator beginArray() { return mData.begin(); } LLSD::array_iterator endArray() { return mData.end(); } @@ -690,12 +733,31 @@ namespace mData.insert(mData.begin() + index, v); } + void ImplArray::insert(size_t i, LLSD&& v) + { + NEGATIVE_EXIT(i); + DataVector::size_type index = i; + + if (index >= mData.size()) // tbd - sanity check limit for index ? + { + mData.resize(index + 1); + } + + mData.insert(mData.begin() + index, std::move(v)); + } + LLSD& ImplArray::append(const LLSD& v) { mData.push_back(v); return mData.back(); } + LLSD& ImplArray::append(LLSD&& v) + { + mData.push_back(std::move(v)); + return mData.back(); + } + void ImplArray::erase(size_t i) { NEGATIVE_EXIT(i); @@ -763,6 +825,14 @@ LLSD::Impl::~Impl() --sOutstandingCount; } +void LLSD::Impl::destruct(Impl*& var) +{ + if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0) + { + delete var; + } +} + void LLSD::Impl::reset(Impl*& var, Impl* impl) { if (impl && impl->mUseCount != STATIC_USAGE_COUNT) @@ -961,7 +1031,7 @@ namespace LLSD::LLSD() : impl(0) { ALLOC_LLSD_OBJECT; } -LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0); } +LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::destruct(impl); } LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT; assign(other); } void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); } @@ -1037,13 +1107,31 @@ LLSD LLSD::emptyMap() bool LLSD::has(const std::string_view k) const { return safe(impl).has(k); } LLSD LLSD::get(const std::string_view k) const { return safe(impl).get(k); } LLSD LLSD::getKeys() const { return safe(impl).getKeys(); } +void LLSD::insert(std::string&& k, const LLSD& v) { makeMap(impl).insert(std::move(k), v); } +void LLSD::insert(std::string&& k, LLSD&& v) { makeMap(impl).insert(std::move(k), std::move(v)); } void LLSD::insert(std::string_view k, const LLSD& v) { makeMap(impl).insert(k, v); } +void LLSD::insert(std::string_view k, LLSD&& v) { makeMap(impl).insert(k, std::move(v)); } +LLSD& LLSD::with(std::string&& k, const LLSD& v) + { + makeMap(impl).insert(std::move(k), v); + return *this; + } +LLSD& LLSD::with(std::string&& k, LLSD&& v) + { + makeMap(impl).insert(std::move(k), std::move(v)); + return *this; + } LLSD& LLSD::with(std::string_view k, const LLSD& v) { makeMap(impl).insert(k, v); return *this; } +LLSD& LLSD::with(std::string_view k, LLSD&& v) + { + makeMap(impl).insert(k, std::move(v)); + return *this; + } void LLSD::erase(const String& k) { makeMap(impl).erase(k); } LLSD& LLSD::operator[](const std::string_view k) @@ -1051,6 +1139,13 @@ LLSD& LLSD::operator[](const std::string_view k) LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; return makeMap(impl).ref(k); } + +LLSD& LLSD::operator[](std::string&& k) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; + return makeMap(impl).ref(std::move(k)); +} + const LLSD& LLSD::operator[](const std::string_view k) const { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; @@ -1064,18 +1159,33 @@ LLSD LLSD::emptyArray() return v; } +LLSD LLSD::emptyReservedArray(size_t size) +{ + LLSD v; + makeArray(v.impl).reserve(size); + return v; +} + size_t LLSD::size() const { return safe(impl).size(); } LLSD LLSD::get(Integer i) const { return safe(impl).get(i); } void LLSD::set(Integer i, const LLSD& v){ makeArray(impl).set(i, v); } +void LLSD::set(Integer i, LLSD&& v) { makeArray(impl).set(i, std::move(v)); } void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); } +void LLSD::insert(Integer i, LLSD&& v) { makeArray(impl).insert(i, std::move(v)); } LLSD& LLSD::with(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); return *this; } +LLSD& LLSD::with(Integer i, LLSD&& v) + { + makeArray(impl).insert(i, std::move(v)); + return *this; + } LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); } +LLSD& LLSD::append(LLSD&& v) { return makeArray(impl).append(std::move(v)); } void LLSD::erase(Integer i) { makeArray(impl).erase(i); } LLSD& LLSD::operator[](size_t i) @@ -1143,6 +1253,22 @@ LLSD::reverse_array_iterator LLSD::rendArray() { return makeArray(impl) namespace llsd { +LLSD::Real string_to_real(std::string_view in_string) +{ + LLSD::Real v = 0.0; + boost::iostreams::stream i_stream(in_string.data(), in_string.size()); + i_stream >> v; + + // we would probably like to ignore all trailing whitespace as + // well, but for now, simply eat the next character, and make + // sure we reached the end of the string. + // *NOTE: gcc 2.95 does not generate an eof() event on the + // stream operation above, so we manually get here to force it + // across platforms. + int c = i_stream.get(); + return ((EOF == c) ? v : 0.0); +} + U32 allocationCount() { return LLSD::Impl::sAllocationCount; } U32 outstandingCount() { return LLSD::Impl::sOutstandingCount; } diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index d2b35488316..afe35a65ba0 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -34,6 +34,7 @@ #include "stdtypes.h" #include "lldate.h" +#include "llstl.h" #include "lluri.h" #include "lluuid.h" @@ -321,11 +322,34 @@ class LL_COMMON_API LLSD bool has(const std::string_view) const; LLSD get(const std::string_view) const; LLSD getKeys() const; // Return an LLSD array with keys as strings + void insert(const char* k, const LLSD& v) + { + return insert(std::string_view(k), v); + } + void insert(const char* k , LLSD&& v) + { + return insert(std::string_view(k), std::move(v)); + } + void insert(std::string&&, const LLSD&); + void insert(std::string&&, LLSD&&); void insert(std::string_view, const LLSD&); + void insert(std::string_view, LLSD&&); void erase(const String&); + LLSD& with(const char* k, const LLSD& v) + { + return with(std::string_view(k), v); + } + LLSD& with(const char* k, LLSD&& v) + { + return with(std::string_view(k), std::move(v)); + } + LLSD& with(std::string&&, const LLSD&); + LLSD& with(std::string&&, LLSD&&); LLSD& with(std::string_view, const LLSD&); + LLSD& with(std::string_view, LLSD&&); LLSD& operator[](const std::string_view); + LLSD& operator[](std::string&&); LLSD& operator[](const char* c) { return c ? (*this)[std::string_view(c)] : *this; @@ -339,14 +363,22 @@ class LL_COMMON_API LLSD /** @name Array Values */ //@{ + // Allocate an empty array static LLSD emptyArray(); + // Allocate an array with internal storage reserved but not initialized like a std::vector + static LLSD emptyReservedArray(size_t size); + LLSD get(Integer) const; void set(Integer, const LLSD&); + void set(Integer, LLSD&&); void insert(Integer, const LLSD&); + void insert(Integer, LLSD&&); LLSD& append(const LLSD&); + LLSD& append(LLSD&&); void erase(Integer); LLSD& with(Integer, const LLSD&); + LLSD& with(Integer, LLSD&&); // accept size_t so we can index relative to size() const LLSD& operator[](size_t) const; @@ -366,8 +398,9 @@ class LL_COMMON_API LLSD //@{ size_t size() const; - typedef std::map::iterator map_iterator; - typedef std::map::const_iterator map_const_iterator; + using llsd_map_t = std::map>; + typedef llsd_map_t::iterator map_iterator; + typedef llsd_map_t::const_iterator map_const_iterator; map_iterator beginMap(); map_iterator endMap(); @@ -512,6 +545,8 @@ LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd); namespace llsd { + // Used by LLSD::ImplString to convert string type to real + LLSD::Real string_to_real(std::string_view in_string); #ifdef LLSD_DEBUG_INFO /** @name Unit Testing Interface */ diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp index 655869a704f..bb806f32eb4 100644 --- a/indra/llcommon/llsdjson.cpp +++ b/indra/llcommon/llsdjson.cpp @@ -66,7 +66,7 @@ LLSD LlsdFromJson(const boost::json::value& val) const boost::json::array& array = val.as_array(); size_t size = array.size(); // allocate elements 0 .. (size() - 1) to avoid incremental allocation - if (! array.empty()) + if (!array.empty()) { result[size - 1] = LLSD(); } @@ -80,7 +80,7 @@ LLSD LlsdFromJson(const boost::json::value& val) result = LLSD::emptyMap(); for (const auto& element : val.as_object()) { - result[element.key()] = LlsdFromJson(element.value()); + result[std::string_view(element.key())] = LlsdFromJson(element.value()); } break; } diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 37af366a20b..ee7f0b01ccd 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -775,7 +775,8 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) c // There must be a value for every key, thus // child_count must be greater than 0. parse_count += count; - map.insert(name, child); + map.insert(std::move(name), std::move(child)); // Move as name will be filled on next iteration + name.clear(); } else { @@ -822,7 +823,7 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_dept else { parse_count += count; - array.append(child); + array.append(std::move(child)); } c = get(istr); } @@ -841,7 +842,7 @@ bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const auto count = deserialize_string(istr, value, mMaxBytesLeft); if(PARSE_FAILURE == count) return false; account(count); - data = value; + data = std::move(value); return true; } @@ -872,10 +873,10 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const if(len) { value.resize(len); - account(fullread(istr, (char *)&value[0], len)); + account(fullread(istr, (char*)value.data(), len)); } c = get(istr); // strip off the trailing double-quote - data = value; + data = std::move(value); } else if(0 == strncmp("b64", buf, 3)) { @@ -885,7 +886,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const std::stringstream coded_stream; get(istr, *(coded_stream.rdbuf()), '\"'); c = get(istr); - std::string encoded(coded_stream.str()); + std::string encoded(std::move(coded_stream).str()); S32 len = apr_base64_decode_len(encoded.c_str()); std::vector value; if(len) @@ -894,7 +895,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const len = apr_base64_decode_binary(&value[0], encoded.c_str()); value.resize(len); } - data = value; + data = std::move(value); } else if(0 == strncmp("b16", buf, 3)) { @@ -925,7 +926,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const // copy the data out of the byte buffer value.insert(value.end(), byte_buffer, write); } - data = value; + data = std::move(value); } else { @@ -1077,7 +1078,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con } else { - data = value; + data = std::move(value); account(cnt); } if(istr.fail()) @@ -1094,7 +1095,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con std::string value; if(parseString(istr, value)) { - data = value; + data = std::move(value); } else { @@ -1159,7 +1160,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con value.resize(size); account(fullread(istr, (char*)&value[0], size)); } - data = value; + data = std::move(value); } if(istr.fail()) { @@ -1218,7 +1219,7 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) con // There must be a value for every key, thus child_count // must be greater than 0. parse_count += child_count; - map.insert(name, child); + map.insert(std::move(name), std::move(child)); } else { @@ -1238,13 +1239,12 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) con S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const { - array = LLSD::emptyArray(); U32 value_nbo = 0; read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ S32 size = (S32)ntohl(value_nbo); - // *FIX: This would be a good place to reserve some space in the - // array... + // Preallocate array to avoid incremental allocation + array = LLSD::emptyReservedArray(size); S32 parse_count = 0; S32 count = 0; @@ -1260,7 +1260,7 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) if(child_count) { parse_count += child_count; - array.append(child); + array.append(std::move(child)); } ++count; c = istr.peek(); @@ -1279,18 +1279,15 @@ bool LLSDBinaryParser::parseString( std::istream& istr, std::string& value) const { - // *FIX: This is memory inefficient. U32 value_nbo = 0; read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ S32 size = (S32)ntohl(value_nbo); if(mCheckLimits && (size > mMaxBytesLeft)) return false; if(size < 0) return false; - std::vector buf; if(size) { - buf.resize(size); - account(fullread(istr, &buf[0], size)); - value.assign(buf.begin(), buf.end()); + value.resize(size); + account(fullread(istr, value.data(), size)); } return true; } @@ -1785,7 +1782,7 @@ llssize deserialize_string_delim( } } - value = write_buffer.str(); + value = std::move(write_buffer).str(); return count; } @@ -1806,15 +1803,12 @@ llssize deserialize_string_raw( { // We probably have a valid raw string. determine // the size, and read it. - // *FIX: This is memory inefficient. - auto len = strtol(buf + 1, NULL, 0); + auto len = strtol(buf + 1, nullptr, 0); if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE; - std::vector buf; if(len) { - buf.resize(len); - count += fullread(istr, (char *)&buf[0], len); - value.assign(buf.begin(), buf.end()); + value.resize(len); + count += fullread(istr, value.data(), len); } c = istr.get(); ++count; @@ -2170,7 +2164,7 @@ std::string zip_llsd(LLSD& data) return std::string(); } - std::string source = llsd_strm.str(); + std::string source = std::move(llsd_strm).str(); U8 out[CHUNK]; diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 6396caf8d53..f399c51608e 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -31,6 +31,8 @@ #include #include "apr_base64.h" +#include +#include #include extern "C" @@ -645,7 +647,7 @@ void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Ch if (mCurrentKey.empty()) { return startSkipping(); } LLSD& map = *mStack.back(); - LLSD& newElement = map[mCurrentKey]; + LLSD& newElement = map[std::move(mCurrentKey)]; mStack.push_back(&newElement); mCurrentKey.clear(); @@ -709,7 +711,8 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name) return; case ELEMENT_KEY: - mCurrentKey = mCurrentContent; + mCurrentKey = std::move(mCurrentContent); // This is safe to move as we are in the end element handler + mCurrentContent.clear(); // Ensure mCurrentContent is empty for subsequent use return; default: @@ -742,14 +745,22 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name) } else { - value = LLSD(mCurrentContent).asInteger(); + // This must treat "1.23" not as an error, but as a number, which is + // then truncated down to an integer. Hence, this code doesn't call + // std::istringstream::operator>>(int&), which would not consume the + // ".23" portion. + + // Utilizes implementation used internally by LLSD::ImplString::asInteger + value = (int)llsd::string_to_real(mCurrentContent); } } break; case ELEMENT_REAL: { - value = LLSD(mCurrentContent).asReal(); + // Utilizes implementation used internally by LLSD::ImplString::asReal + value = llsd::string_to_real(mCurrentContent); + // removed since this breaks when locale has decimal separator that isn't '.' // investigated changing local to something compatible each time but deemed higher // risk that just using LLSD.asReal() each time. @@ -766,19 +777,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name) break; case ELEMENT_STRING: - value = mCurrentContent; + value = std::move(mCurrentContent); // This is safe to move as we are in the end element handler and this is cleared below break; case ELEMENT_UUID: - value = LLSD(mCurrentContent).asUUID(); + value = LLUUID(mCurrentContent); break; case ELEMENT_DATE: - value = LLSD(mCurrentContent).asDate(); + value = LLDate(mCurrentContent); break; case ELEMENT_URI: - value = LLSD(mCurrentContent).asURI(); + value = LLURI(mCurrentContent); break; case ELEMENT_BINARY: @@ -787,15 +798,14 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name) // created by python and other non-linden systems - DEV-39358 // Fortunately we have very little binary passing now, // so performance impact shold be negligible. + poppy 2009-09-04 - boost::regex r; - r.assign("\\s"); + static const boost::regex r("\\s"); std::string stripped = boost::regex_replace(mCurrentContent, r, ""); S32 len = apr_base64_decode_len(stripped.c_str()); std::vector data; data.resize(len); len = apr_base64_decode_binary(&data[0], stripped.c_str()); data.resize(len); - value = data; + value = std::move(data); break; } diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 3fba8602eed..e6989211ae9 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -25,10 +25,10 @@ #ifndef LLSINGLETON_H #define LLSINGLETON_H -#include #include #include #include +#include #include #include "mutex.h" #include "lockstatic.h" @@ -61,7 +61,7 @@ class LLSingletonBase static vec_t dep_sort(); // we directly depend on these other LLSingletons - typedef boost::unordered_set set_t; + typedef std::unordered_set set_t; set_t mDepends; protected: diff --git a/indra/llcommon/llstaticstringtable.h b/indra/llcommon/llstaticstringtable.h index 66ba3487c4e..edff955ee74 100644 --- a/indra/llcommon/llstaticstringtable.h +++ b/indra/llcommon/llstaticstringtable.h @@ -29,9 +29,10 @@ #define LL_STATIC_STRING_TABLE_H #include "lldefs.h" -#include #include "llstl.h" +#include + class LLStaticHashedString { public: @@ -74,7 +75,7 @@ struct LLStaticStringHasher template< typename MappedObject > class LL_COMMON_API LLStaticStringTable - : public boost::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher > + : public std::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher > { }; diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 7d41c42ba7f..7a1c7caf828 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #ifdef LL_LINUX @@ -229,12 +230,10 @@ void delete_and_clear_array(T*& ptr) template inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_type const& key) { - // Typedef here avoids warnings because of new c++ naming rules. - typedef typename T::const_iterator map_iter; - map_iter iter = inmap.find(key); + auto iter = inmap.find(key); if(iter == inmap.end()) { - return NULL; + return nullptr; } else { @@ -243,8 +242,8 @@ inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_ty }; // helper function which returns true if key is in inmap. -template -inline bool is_in_map(const std::map& inmap, const K& key) +template +inline bool is_in_map(const T& inmap, typename T::key_type const& key) { if(inmap.find(key) == inmap.end()) { @@ -260,12 +259,10 @@ inline bool is_in_map(const std::map& inmap, const K& key) // To replace LLSkipMap getIfThere, use: // get_if_there(map, key, 0) // WARNING: Make sure default_value (generally 0) is not a valid map entry! -template -inline T get_if_there(const std::map& inmap, const K& key, T default_value) +template +inline typename T::mapped_type get_if_there(const T& inmap, typename T::key_type const& key, typename T::mapped_type default_value) { - // Typedef here avoids warnings because of new c++ naming rules. - typedef typename std::map::const_iterator map_iter; - map_iter iter = inmap.find(key); + auto iter = inmap.find(key); if(iter == inmap.end()) { return default_value; @@ -709,5 +706,24 @@ struct ll_template_cast_impl \ } \ } +// Transparent string hashing helper for use with std::unordered_* +// std::unordered_map> +namespace ll +{ + struct string_hash + { + using is_transparent = void; + [[nodiscard]] size_t operator()(char const* rhs) const { return std::hash{}(rhs); } + [[nodiscard]] size_t operator()(std::string_view rhs) const { return std::hash{}(rhs); } + [[nodiscard]] size_t operator()(const std::string& rhs) const { return std::hash{}(rhs); } + }; +} // namespace ll + +// Specialize ostream for std::type_index to allow log output +inline std::ostream& operator<<(std::ostream& s, std::type_index type) +{ + s << type.name(); + return s; +} #endif // LL_LLSTL_H diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index ca1cf03c4d0..f91aadccc0d 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -26,6 +26,7 @@ #ifndef LL_LLUUID_H #define LL_LLUUID_H +#include #include #include #include @@ -176,15 +177,27 @@ namespace std { inline size_t operator()(const LLUUID& id) const noexcept { - return (size_t)id.getDigest64(); + size_t h = 0; + // Golden ratio hash with avalanche mixing + // Process 8 bytes at a time by manually constructing 64-bit values + // Shift by 31: mixes upper half into lower half for better bit distribution + // Shift by 47: ensures highest bits influence final hash output + for (int i = 0; i < UUID_BYTES; i += 8) { + size_t chunk = (size_t)id.mData[i] | ((size_t)id.mData[i+1] << 8) | + ((size_t)id.mData[i+2] << 16) | ((size_t)id.mData[i+3] << 24) | + ((size_t)id.mData[i+4] << 32) | ((size_t)id.mData[i+5] << 40) | + ((size_t)id.mData[i+6] << 48) | ((size_t)id.mData[i+7] << 56); + h ^= (chunk * 0x9e3779b97f4a7c15ULL) ^ (h >> 31) ^ (h >> 47); + } + return h; } }; } -// For use with boost containers. +// For use with boost::container_hash inline size_t hash_value(const LLUUID& id) noexcept { - return (size_t)id.getDigest64(); + return std::hash{}(id); } #endif // LL_LLUUID_H diff --git a/indra/llcommon/llwatchdog.cpp b/indra/llcommon/llwatchdog.cpp index fa240a9ed77..1622aeb1808 100644 --- a/indra/llcommon/llwatchdog.cpp +++ b/indra/llcommon/llwatchdog.cpp @@ -28,6 +28,7 @@ #include "linden_common.h" #include "llwatchdog.h" +#include "llmutex.h" #include "llthread.h" constexpr U32 WATCHDOG_SLEEP_TIME_USEC = 1000000U; @@ -86,7 +87,7 @@ void LLWatchdogEntry::start() void LLWatchdogEntry::stop() { // this can happen very late in the shutdown sequence - if (!LLWatchdog::wasDeleted()) + if (LLWatchdog::instanceExists()) { LLWatchdog::getInstance()->remove(this); } @@ -172,6 +173,17 @@ void LLWatchdog::add(LLWatchdogEntry* e) { lockThread(); mSuspects.insert(e); + + if (!mFrozeList.empty()) + { + mFrozeList.erase(e); + if (mFrozeList.empty()) + { + // Clear error marker file if there is no frozen threads, + // viewer is responsive again. + mClearMarkerFnc(); + } + } unlockThread(); } @@ -182,7 +194,12 @@ void LLWatchdog::remove(LLWatchdogEntry* e) unlockThread(); } -void LLWatchdog::init(func_t set_error_state_callback) +void LLWatchdog::init( + create_marker_func_t error_state_callback, + clear_marker_func_t clear_marker_callback, + report_func_t report_callback, + notify_func_t notify_callback, + bool crash_on_freeze) { if (!mSuspectsAccessMutex && !mTimer) { @@ -195,7 +212,11 @@ void LLWatchdog::init(func_t set_error_state_callback) // start needs to use the mSuspectsAccessMutex mTimer->start(); } - mCreateMarkerFnc = set_error_state_callback; + mCreateMarkerFnc = error_state_callback; + mClearMarkerFnc = clear_marker_callback; + mCrashReportFnc = report_callback; + mNotifyFnc = notify_callback; + mCrashOnFreeze = crash_on_freeze; } void LLWatchdog::cleanup() @@ -250,21 +271,45 @@ void LLWatchdog::run() mTimer->stop(); } - // Sets error marker file - mCreateMarkerFnc(); - // Todo1: Warn user? - // Todo2: We probably want to report even if 5 seconds passed, just not error 'yet'. std::string last_state = (*result)->getLastState(); - if (last_state.empty()) + std::string description = "Watchdog timer for thread " + (*result)->getThreadName() + " expired"; + if (!last_state.empty()) { - LL_ERRS() << "Watchdog timer for thread " << (*result)->getThreadName() - << " expired; assuming viewer is hung and crashing" << LL_ENDL; + description += " with state: " + last_state; + } + description += "; assuming viewer is hung and crashing"; + + if (!mCrashOnFreeze) + { + // Sets watchdog marker file + mCreateMarkerFnc(false); + // If it's mainloop and it somehow recovers, it will re-add itself + mSuspects.erase(*result); + mFrozeList.insert(*result); + LL_WARNS() << description << LL_ENDL; } else { - LL_ERRS() << "Watchdog timer for thread " << (*result)->getThreadName() - << " expired with state: " << last_state - << "; assuming viewer is hung and crashing" << LL_ENDL; + + if (!mCrashReportFnc(description)) + { + // Sets error marker file + mCreateMarkerFnc(true); + // If false is returned, then we failed to report the issue to bugsplat, + // instead, Notify user, then crash viewer. + // Todo: ask user if viewer should quit or wait? + mNotifyFnc(); + LL_ERRS() << description << LL_ENDL; + } + else + { + // Sets watchdog marker file + mCreateMarkerFnc(false); + // Already reported, don't report again. + // If it's mainloop and it somehow recovers, it will re-add itself + mSuspects.erase(result); + mFrozeList.insert(*result); + } } } } diff --git a/indra/llcommon/llwatchdog.h b/indra/llcommon/llwatchdog.h index fded881bb8d..f138fbccb05 100644 --- a/indra/llcommon/llwatchdog.h +++ b/indra/llcommon/llwatchdog.h @@ -83,18 +83,26 @@ class LLWatchdogTimeout : public LLWatchdogEntry }; class LLWatchdogTimerThread; // Defined in the cpp -class LLWatchdog : public LLSingleton +class LLWatchdog : public LLSimpleton { - LLSINGLETON(LLWatchdog); +public: + LLWatchdog(); ~LLWatchdog(); -public: // Add an entry to the watchdog. void add(LLWatchdogEntry* e); void remove(LLWatchdogEntry* e); - typedef std::function func_t; - void init(func_t set_error_state_callback); + typedef std::function create_marker_func_t; + typedef std::function clear_marker_func_t; + typedef std::function report_func_t; + typedef std::function notify_func_t; + void init( + create_marker_func_t error_state_callback, + clear_marker_func_t clear_marker_callback, + report_func_t report_callback, + notify_func_t notify_callback, + bool crash_on_freeze); void run(); void cleanup(); @@ -105,14 +113,19 @@ class LLWatchdog : public LLSingleton typedef std::set SuspectsRegistry; SuspectsRegistry mSuspects; + SuspectsRegistry mFrozeList; LLMutex* mSuspectsAccessMutex; LLWatchdogTimerThread* mTimer; U64 mLastClockCount; + bool mCrashOnFreeze; // At the moment watchdog expects app to set markers in mCreateMarkerFnc, // but technically can be used to set any error states or do some cleanup // or show warnings. - func_t mCreateMarkerFnc; + create_marker_func_t mCreateMarkerFnc; + clear_marker_func_t mClearMarkerFnc; + report_func_t mCrashReportFnc; + notify_func_t mNotifyFnc; }; #endif // LL_LLTHREADWATCHDOG_H diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp index 0407d6c3e94..67c23358edf 100644 --- a/indra/llcommon/workqueue.cpp +++ b/indra/llcommon/workqueue.cpp @@ -281,12 +281,30 @@ bool LL::WorkQueue::done() bool LL::WorkQueue::post(const Work& callable) { - return mQueue.pushIfOpen(callable); + try + { + return mQueue.pushIfOpen(callable); + } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS("LLCoros") << "Bad memory allocation in WorkQueue::post" << LL_ENDL; + return false; + } } bool LL::WorkQueue::tryPost(const Work& callable) { - return mQueue.tryPush(callable); + try + { + return mQueue.tryPush(callable); + } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS("LLCoros") << "Bad memory allocation in WorkQueue::tryPost" << LL_ENDL; + return false; + } } LL::WorkQueue::Work LL::WorkQueue::pop_() diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index 190539cea59..22bb50074ae 100644 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -44,6 +44,7 @@ #include "stringize.h" #include "llstring.h" #include +#include "llprocess.h" #include #include @@ -1100,6 +1101,61 @@ LLDir::SepOff LLDir::needSep(const std::string& path, const std::string& name) c return SepOff(false, 0); } +void LLDir::openDir(const std::string& filepath) +{ + if (filepath.empty()) + { + LL_WARNS() << "Cannot open file browser: filepath is empty" << LL_ENDL; + return; + } + + // Extract directory path from full filepath + std::string dir_path = getDirName(filepath); + + LLProcess::Params params; + +#if LL_WINDOWS + // Windows: Use explorer.exe with /select flag to highlight the file + std::string system_root = LLStringUtil::getenv("SystemRoot"); + if (system_root.empty()) + { + system_root = LLStringUtil::getenv("WINDIR"); + } + if (system_root.empty()) + { + LL_WARNS() << "Neither SystemRoot nor WINDIR environment variable is set" << LL_ENDL; + system_root = "C:\\Windows"; // Last resort fallback + } + params.executable = system_root + "\\explorer.exe"; + params.args.add("/select,"); + params.args.add(filepath); +#elif LL_DARWIN + // macOS: Use 'open' command with -R flag to reveal in Finder + params.executable = "/usr/bin/open"; + params.args.add("-R"); + params.args.add(filepath); +#elif LL_LINUX + // Linux: Use xdg-open to open the directory + // Note: Most file managers don't support file selection, so we open the directory + params.executable = "/usr/bin/xdg-open"; + params.args.add(dir_path); +#else + LL_WARNS() << "Platform not supported for file browser opening" << LL_ENDL; + return; +#endif + + params.autokill = false; // Don't kill the file browser when viewer exits + + if (!LLProcess::create(params)) + { + LL_WARNS() << "Failed to open file browser for: " << filepath << LL_ENDL; + } + else + { + LL_INFOS() << "Opened file browser for: " << filepath << LL_ENDL; + } +} + void dir_exists_or_crash(const std::string &dir_name) { #if LL_WINDOWS diff --git a/indra/llfilesystem/lldir.h b/indra/llfilesystem/lldir.h index b0d2b6aada8..3c8e2e2da67 100644 --- a/indra/llfilesystem/lldir.h +++ b/indra/llfilesystem/lldir.h @@ -194,6 +194,9 @@ class LLDir virtual void dumpCurrentDirectories(LLError::ELevel level = LLError::LEVEL_DEBUG); + // Open the system file browser to reveal a file or directory + void openDir(const std::string& filepath); + // Utility routine std::string buildSLOSCacheDir() const; diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index e971e1885a2..dd7d1a043ff 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -91,6 +91,8 @@ LLDiskCache::LLDiskCache(const std::string& cache_dir, // asset will have to be re-requested. void LLDiskCache::purge() { + LL_PROFILE_ZONE_SCOPED; + if (mEnableCacheDebugInfo) { LL_INFOS() << "Total dir size before purge is " << dirFileSize(sCacheDir) << LL_ENDL; @@ -112,6 +114,10 @@ void LLDiskCache::purge() boost::filesystem::directory_iterator iter(cache_path, ec); while (iter != boost::filesystem::directory_iterator() && !ec.failed()) { + if(!LLApp::isRunning()) + { + return; + } if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed()) { if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos) @@ -150,6 +156,10 @@ void LLDiskCache::purge() uintmax_t file_size_total = 0; for (file_info_t& entry : file_info) { + if (!LLApp::isRunning()) + { + return; + } file_size_total += entry.second.first; bool should_remove = file_size_total > mMaxSizeBytes; @@ -176,6 +186,10 @@ void LLDiskCache::purge() // Logging thousands of file results can take hundreds of milliseconds for (size_t i = 0; i < file_info.size(); ++i) { + if (!LLApp::isRunning()) + { + return; + } const file_info_t& entry = file_info[i]; const bool removed = file_removed[i]; const std::string action = removed ? "DELETE:" : "KEEP:"; diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp index 541266af4f6..728ff396ef0 100644 --- a/indra/llfilesystem/llfilesystem.cpp +++ b/indra/llfilesystem/llfilesystem.cpp @@ -77,11 +77,10 @@ bool LLFileSystem::getExists(const LLUUID& file_id, const LLAssetType::EType fil LL_PROFILE_ZONE_SCOPED; const std::string filename = LLDiskCache::metaDataToFilepath(file_id, file_type); - llifstream file(filename, std::ios::binary); - if (file.is_open()) + boost::system::error_code ec; + if (boost::filesystem::exists(filename, ec) && boost::filesystem::is_regular_file(filename, ec)) { - file.seekg(0, std::ios::end); - return file.tellg() > 0; + return boost::filesystem::file_size(filename, ec) > 0; } return false; } @@ -120,15 +119,12 @@ S32 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType fi { const std::string filename = LLDiskCache::metaDataToFilepath(file_id, file_type); - S32 file_size = 0; - llifstream file(filename, std::ios::binary); - if (file.is_open()) + boost::system::error_code ec; + if (boost::filesystem::exists(filename, ec) && boost::filesystem::is_regular_file(filename, ec)) { - file.seekg(0, std::ios::end); - file_size = (S32)file.tellg(); + return static_cast(boost::filesystem::file_size(filename, ec)); } - - return file_size; + return 0; } bool LLFileSystem::read(U8* buffer, S32 bytes) diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 6b14b68c789..1fb61673bd3 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -27,10 +27,11 @@ #ifndef LL_LLIMAGE_H #define LL_LLIMAGE_H -#include "lluuid.h" -#include "llstring.h" +#include "llmutex.h" #include "llpointer.h" +#include "llstring.h" #include "lltrace.h" +#include "lluuid.h" constexpr S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2 constexpr S32 MAX_IMAGE_MIP = 12; // 4096x4096 diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 3defad8f3b0..f126accfb86 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -1017,10 +1017,9 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) if (i->first == INV_THUMBNAIL_LABEL) { const LLSD &thumbnail_map = i->second; - const std::string w = INV_ASSET_ID_LABEL; - if (thumbnail_map.has(w)) + if (thumbnail_map.has(INV_ASSET_ID_LABEL)) { - mThumbnailUUID = thumbnail_map[w]; + mThumbnailUUID = thumbnail_map[INV_ASSET_ID_LABEL]; } /* Example: asset_id @@ -1033,7 +1032,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) 1 */ continue; - } + } if (i->first == INV_THUMBNAIL_ID_LABEL) { @@ -1044,10 +1043,9 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) if (i->first == INV_FAVORITE_LABEL) { const LLSD& favorite_map = i->second; - const std::string w = INV_TOGGLED_LABEL; - if (favorite_map.has(w)) + if (favorite_map.has(INV_TOGGLED_LABEL)) { - mFavorite = favorite_map[w].asBoolean(); + mFavorite = favorite_map[INV_TOGGLED_LABEL].asBoolean(); } continue; } @@ -1111,7 +1109,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) LLSD const &label = i->second; if (label.isString()) { - mType = LLAssetType::lookup(label.asString().c_str()); + mType = LLAssetType::lookup(label.asStringRef().c_str()); } else if (label.isInteger()) { @@ -1126,7 +1124,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) LLSD const &label = i->second; if (label.isString()) { - mInventoryType = LLInventoryType::lookup(label.asString().c_str()); + mInventoryType = LLInventoryType::lookup(label.asStringRef().c_str()); } else if (label.isInteger()) { @@ -1290,7 +1288,7 @@ void LLInventoryCategory::packMessage(LLMessageSystem* msg) const bool LLInventoryCategory::fromLLSD(const LLSD& sd) { - std::string w; + std::string_view w; w = INV_FOLDER_ID_LABEL_WS; if (sd.has(w)) diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 7eba9494a62..e7ac6bdb31e 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -615,6 +615,11 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco return false; } } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS() << "Bad memory allocation in J2C KDU" << LL_ENDL; + } catch (const KDUError& msg) { base.setLastError(msg.what()); diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index b3cb278d599..c74ea3e42b4 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -912,7 +912,7 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai case LL_PCODE_HOLE_CIRCLE: case LL_PCODE_HOLE_SAME: default: - addHole(params, true, circle_detail, 0, hollow, 1.f); + addHole(params, false, circle_detail, 0, hollow, 1.f); break; } } @@ -4943,9 +4943,17 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src) mOctree(NULL), mOctreeTriangles(NULL) { - mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3); - mCenter = mExtents+2; - *this = src; + try + { + mExtents = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a) * 3); + mCenter = mExtents + 2; + *this = src; + } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS("LLVolume") << "Bad memory allocation in LLVolumeFace" << LL_ENDL; + } } LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) @@ -5163,7 +5171,7 @@ void LLVolumeFace::remap() // Documentation for meshopt_generateVertexRemapMulti claims that remap should use vertice count // but all examples use indice count. There are out of bounds crashes when using vertice count. // To be on the safe side use bigger of the two. - std::vector remap(llmax(mNumIndices, mNumVertices)); + std::vector remap(llmax(mNumIndices, mNumVertices), 0); S32 remap_vertices_count = static_cast(LLMeshOptimizer::generateRemapMultiU16(&remap[0], mIndices, mNumIndices, @@ -5681,7 +5689,12 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) catch (std::bad_alloc&) { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS("LLCoros") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL; + LL_ERRS("LLVolume") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL; + } + catch (...) + { + LL_WARNS_ONCE("LLVolume") << "Mikktspace::genTangSpace() failed" << LL_ENDL; + return false; } @@ -5703,7 +5716,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) catch (std::bad_alloc&) { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS("LLCoros") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL; + LL_ERRS("LLVOLUME") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL; } U32 stream_count = data.w.empty() ? 4 : 5; @@ -5720,7 +5733,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) catch (std::bad_alloc&) { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS("LLCoros") << "Failed to allocate memory for VertexRemap: " << (S32)data.p.size() << LL_ENDL; + LL_ERRS("LLVolume") << "Failed to allocate memory for VertexRemap: " << (S32)data.p.size() << LL_ENDL; } } @@ -5732,7 +5745,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) if (mNumVertices == 0) { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS("LLCoros") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL; + LL_ERRS("LLVolume") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL; } if (!data.w.empty()) diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index bb0c94d513c..d8f649140fc 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -25,6 +25,7 @@ #include "linden_common.h" +#include "llmutex.h" #include "llvolumemgr.h" #include "llvolume.h" diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 196ecdcf7d9..0e11dca8760 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -155,6 +155,7 @@ class LLVector3 friend const LLVector3& operator*=(LLVector3 &a, const LLVector3 &b); // Returns a * b; friend const LLVector3& operator*=(LLVector3 &a, F32 k); // Return a times scaler k friend const LLVector3& operator/=(LLVector3 &a, F32 k); // Return a divided by scaler k + friend const LLVector3& operator/=(LLVector3& a, const LLVector3& b); friend const LLVector3& operator*=(LLVector3 &a, const LLQuaternion &b); // Returns a * b; friend LLVector3 operator-(const LLVector3 &a); // Return vector -a @@ -460,6 +461,14 @@ inline const LLVector3& operator/=(LLVector3& a, F32 k) return a; } +inline const LLVector3& operator/=(LLVector3& a, const LLVector3& b) +{ + a.mV[VX] /= b.mV[VX]; + a.mV[VY] /= b.mV[VY]; + a.mV[VZ] /= b.mV[VZ]; + return a; +} + inline LLVector3 operator-(const LLVector3& a) { return LLVector3(-a.mV[VX], -a.mV[VY], -a.mV[VZ]); diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp index 73394543672..76d51fdad0e 100644 --- a/indra/llmeshoptimizer/llmeshoptimizer.cpp +++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp @@ -171,7 +171,6 @@ size_t LLMeshOptimizer::generateRemapMultiU32( // but providing indices helps with removing unused vertices U64 indeces_cmp = indices ? index_count : vertex_count; - // meshopt_generateVertexRemapMulti will throw an assert if (indices[i] >= vertex_count) return meshopt_generateVertexRemapMulti(&remap[0], indices, indeces_cmp, vertex_count, streams, sizeof(streams) / sizeof(streams[0])); } diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index ebafc53a4de..86b36315dc7 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -276,7 +276,7 @@ void LLAvatarNameCache::handleAvNameCacheSuccess(const LLSD &data, const LLSD &h // Provide some fallback for agents that return errors void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id) { - std::map::iterator existing = mCache.find(agent_id); + cache_t::iterator existing = mCache.find(agent_id); if (existing == mCache.end()) { // there is no existing cache entry, so make a temporary name from legacy @@ -311,7 +311,7 @@ void LLAvatarNameCache::processName(const LLUUID& agent_id, const LLAvatarName& bool updated_account = true; // assume obsolete value for new arrivals by default - std::map::iterator it = mCache.find(agent_id); + cache_t::iterator it = mCache.find(agent_id); if (it != mCache.end() && (*it).second.getAccountName() == av_name.getAccountName()) { @@ -418,7 +418,7 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id, // Retrieve the name and set it to never (or almost never...) expire: when we are using the legacy // protocol, we do not get an expiration date for each name and there's no reason to ask the // data again and again so we set the expiration time to the largest value admissible. - std::map::iterator av_record = LLAvatarNameCache::getInstance()->mCache.find(agent_id); + cache_t::iterator av_record = LLAvatarNameCache::getInstance()->mCache.find(agent_id); LLAvatarName& av_name = av_record->second; av_name.setExpires(MAX_UNREFRESHED_TIME); } @@ -631,7 +631,7 @@ bool LLAvatarNameCache::getName(const LLUUID& agent_id, LLAvatarName *av_name) if (mRunning) { // ...only do immediate lookups when cache is running - std::map::iterator it = mCache.find(agent_id); + cache_t::iterator it = mCache.find(agent_id); if (it != mCache.end()) { *av_name = it->second; @@ -682,7 +682,7 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::getNameCallback(cons if (mRunning) { // ...only do immediate lookups when cache is running - std::map::iterator it = mCache.find(agent_id); + cache_t::iterator it = mCache.find(agent_id); if (it != mCache.end()) { const LLAvatarName& av_name = it->second; @@ -753,13 +753,11 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na LLUUID LLAvatarNameCache::findIdByName(const std::string& name) { - std::map::iterator it; - std::map::iterator end = mCache.end(); - for (it = mCache.begin(); it != end; ++it) + for (const auto& [id, avatar_name] : mCache) { - if (it->second.getUserName() == name) + if (avatar_name.getUserName() == name) { - return it->first; + return id; } } diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 0ddaee2aa14..6743943495a 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -30,8 +30,10 @@ #include "llavatarname.h" // for convenience #include "llsingleton.h" +#include "lluuid.h" #include #include +#include class LLSD; class LLUUID; @@ -161,23 +163,23 @@ class LLAvatarNameCache : public LLSingleton std::string mNameLookupURL; // Accumulated agent IDs for next query against service - typedef std::set ask_queue_t; + using ask_queue_t = std::set; ask_queue_t mAskQueue; // Agent IDs that have been requested, but with no reply. // Maps agent ID to frame time request was made. - typedef std::map pending_queue_t; + using pending_queue_t = std::unordered_map; pending_queue_t mPendingQueue; // Callbacks to fire when we received a name. // May have multiple callbacks for a single ID, which are // represented as multiple slots bound to the signal. // Avoid copying signals via pointers. - typedef std::map signal_map_t; + using signal_map_t = std::unordered_map; signal_map_t mSignalMap; // The cache at last, i.e. avatar names we know about. - typedef std::map cache_t; + using cache_t = std::unordered_map; cache_t mCache; // Time when unrefreshed cached names were checked last. diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 56dfaef873a..95b7bb8c3da 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -179,12 +179,11 @@ void ReplySender::flush() } } - -typedef std::set AskQueue; -typedef std::list ReplyQueue; -typedef std::map PendingQueue; -typedef std::map Cache; -typedef std::map ReverseCache; +using AskQueue = std::set; +using ReplyQueue = std::list; +using PendingQueue = std::unordered_map; +using Cache = std::unordered_map; +using ReverseCache = std::unordered_map; class LLCacheName::Impl { @@ -214,7 +213,7 @@ class LLCacheName::Impl Impl(LLMessageSystem* msg); ~Impl(); - bool getName(const LLUUID& id, std::string& first, std::string& last, std::map& default_names); + bool getName(const LLUUID& id, std::string& first, std::string& last, cache_map_t& default_names); boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback); void addPending(const LLUUID& id, const LLHost& host); @@ -401,7 +400,7 @@ void LLCacheName::exportFile(std::ostream& ostr) } -bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last, std::map& default_names) +bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last, cache_map_t &default_names) { if(id.isNull()) { diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h index 609387b6dee..a333eac0f55 100644 --- a/indra/llmessage/llcachename.h +++ b/indra/llmessage/llcachename.h @@ -136,7 +136,8 @@ class LLCacheName void localizeCacheName(std::string key, std::string value); private: - std::map mCacheName; + using cache_map_t = std::unordered_map; + cache_map_t mCacheName; class Impl; Impl& impl; diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index b24e5e4fccd..647064f607a 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -37,6 +37,7 @@ #include "llsdserialize.h" #include "boost/json.hpp" // Boost.Json #include "llfilesystem.h" +#include "workqueue.h" #include "message.h" // for getting the port @@ -295,41 +296,73 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons } else { - try + constexpr size_t MAX_BODY_SIZE_THRESHOLD = 65536; + bool posted = false; + // Some messsages (ex: AISAPI) can return large bodies. + // If the body is larger than our threshold, post the + // parsing to the general queue to avoid stalling the + // main thread. + if (response->getBodySize() > MAX_BODY_SIZE_THRESHOLD) { - result = this->handleSuccess(response, status); - } - catch (std::bad_alloc&) - { - LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS("CoreHTTP") << "Failed to allocate memory for response handling." << LL_ENDL; - } - } + response->addRef(); - buildStatusEntry(response, status, result); + LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop"); + LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General"); + posted = main_queue->postTo( + general_queue, + [handler = shared_from_this(), response, status]() // Work done on general queue + { + std::pair result; + result.second = status; + try + { + result.first = handler->handleSuccess(response, result.second); + } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS("CoreHTTP") << "Failed to allocate memory for response handling (threaded)." << LL_ENDL; + } + // LLSD is not thread safe! Be carefull with moving the result around. + return result; + }, + [handler = shared_from_this(), response](std::pair result) mutable // Callback to main thread + { + handler->replyPost(response, result.second, result.first); + response->release(); + }); - if (!status) - { - LLSD &httpStatus = result[HttpCoroutineAdapter::HTTP_RESULTS]; + if (posted) + { + // Thread will do the cleanup and notify the pump. Done. + return; + } + else + { + // For whatever reason, failed to post, clean up and + // do the work on the main thread. + response->release(); + } + } - LLCore::BufferArray *body = response->getBody(); - LLCore::BufferArrayStream bas(body); - LLSD::String bodyData; - bodyData.reserve(response->getBodySize()); - bas >> std::noskipws; - bodyData.assign(std::istream_iterator(bas), std::istream_iterator()); - httpStatus["error_body"] = LLSD(bodyData); - if (getBoolSetting(HTTP_LOGBODY_KEY)) + if (!posted) { - // commenting out, but keeping since this can be useful for debugging - LL_WARNS("CoreHTTP") << "Returned body=" << std::endl << httpStatus["error_body"].asString() << LL_ENDL; + try + { + result = this->handleSuccess(response, status); + } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS("CoreHTTP") << "Failed to allocate memory for response handling." << LL_ENDL; + } } } - mReplyPump.post(result); + replyPost(response, status, result); } -void HttpCoroHandler::buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result) +void HttpCoroHandler::buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result) const { LLSD httpresults = LLSD::emptyMap(); @@ -357,6 +390,31 @@ void HttpCoroHandler::buildStatusEntry(LLCore::HttpResponse *response, LLCore::H result[HttpCoroutineAdapter::HTTP_RESULTS] = httpresults; } +void HttpCoroHandler::replyPost(LLCore::HttpResponse* response, LLCore::HttpStatus &status, LLSD& result) +{ + buildStatusEntry(response, status, result); + + if (!status) + { + LLSD& httpStatus = result[HttpCoroutineAdapter::HTTP_RESULTS]; + + LLCore::BufferArray* body = response->getBody(); + LLCore::BufferArrayStream bas(body); + LLSD::String bodyData; + bodyData.reserve(response->getBodySize()); + bas >> std::noskipws; + bodyData.assign(std::istream_iterator(bas), std::istream_iterator()); + httpStatus["error_body"] = LLSD(bodyData); + if (getBoolSetting(HTTP_LOGBODY_KEY)) + { + // commenting out, but keeping since this can be useful for debugging + LL_WARNS("CoreHTTP") << "Returned body=" << std::endl << httpStatus["error_body"].asString() << LL_ENDL; + } + } + + mReplyPump.post(result); +} + void HttpCoroHandler::writeStatusCodes(LLCore::HttpStatus status, const std::string &url, LLSD &result) { result[HttpCoroutineAdapter::HTTP_RESULTS_SUCCESS] = static_cast(status); @@ -389,8 +447,8 @@ class HttpCoroLLSDHandler : public HttpCoroHandler HttpCoroLLSDHandler(LLEventStream &reply); protected: - virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status); - virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success); + virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) const; + virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success) const; }; //------------------------------------------------------------------------- @@ -400,7 +458,7 @@ HttpCoroLLSDHandler::HttpCoroLLSDHandler(LLEventStream &reply): } -LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) +LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) const { LLSD result; @@ -465,7 +523,7 @@ LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: return result; } -LLSD HttpCoroLLSDHandler::parseBody(LLCore::HttpResponse *response, bool &success) +LLSD HttpCoroLLSDHandler::parseBody(LLCore::HttpResponse *response, bool &success) const { success = true; if (response->getBodySize() == 0) @@ -496,8 +554,8 @@ class HttpCoroRawHandler : public HttpCoroHandler public: HttpCoroRawHandler(LLEventStream &reply); - virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status); - virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success); + virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) const; + virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success) const; }; //------------------------------------------------------------------------- @@ -506,7 +564,7 @@ HttpCoroRawHandler::HttpCoroRawHandler(LLEventStream &reply): { } -LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) +LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) const { LLSD result = LLSD::emptyMap(); @@ -552,7 +610,7 @@ LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:: return result; } -LLSD HttpCoroRawHandler::parseBody(LLCore::HttpResponse *response, bool &success) +LLSD HttpCoroRawHandler::parseBody(LLCore::HttpResponse *response, bool &success) const { success = true; return LLSD(); @@ -571,8 +629,8 @@ class HttpCoroJSONHandler : public HttpCoroHandler public: HttpCoroJSONHandler(LLEventStream &reply); - virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status); - virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success); + virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) const; + virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success) const; }; //------------------------------------------------------------------------- @@ -581,7 +639,7 @@ HttpCoroJSONHandler::HttpCoroJSONHandler(LLEventStream &reply) : { } -LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) +LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) const { LLSD result = LLSD::emptyMap(); @@ -607,7 +665,7 @@ LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: return result; } -LLSD HttpCoroJSONHandler::parseBody(LLCore::HttpResponse *response, bool &success) +LLSD HttpCoroJSONHandler::parseBody(LLCore::HttpResponse *response, bool &success) const { success = true; BufferArray * body(response->getBody()); diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h index 3dbfd6f00db..3072f78911b 100644 --- a/indra/llmessage/llcorehttputil.h +++ b/indra/llmessage/llcorehttputil.h @@ -259,7 +259,7 @@ inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & requ /// +- ["url"] - The URL used to make the call. /// +- ["headers"] - A map of name name value pairs with the HTTP headers. /// -class HttpCoroHandler : public LLCore::HttpHandler +class HttpCoroHandler : public LLCore::HttpHandler, public std::enable_shared_from_this { public: @@ -279,11 +279,12 @@ class HttpCoroHandler : public LLCore::HttpHandler protected: /// this method may modify the status value - virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) = 0; - virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success) = 0; + virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) const = 0; + virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success) const = 0; private: - void buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result); + void buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result) const; + void replyPost(LLCore::HttpResponse* response, LLCore::HttpStatus& status, LLSD& result); LLEventStream &mReplyPump; }; diff --git a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp index 78876f9f365..b7c4b5e591a 100644 --- a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp +++ b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp @@ -75,10 +75,7 @@ LLCDResult LLConvexDecompositionVHACD::quitSystem() LLConvexDecompositionVHACD::LLConvexDecompositionVHACD() { - //Create our vhacd instance and setup default parameters - mVHACD = VHACD::CreateVHACD(); - - mVHACDParameters.m_callback = &mVHACDCallback; + // Setup default parameters mVHACDParameters.m_logger = &mVHACDLogger; mDecompStages[0].mName = "Analyze"; @@ -206,27 +203,33 @@ LLConvexDecompositionVHACD::LLConvexDecompositionVHACD() LLConvexDecompositionVHACD::~LLConvexDecompositionVHACD() { - mBoundDecomp = nullptr; - mDecompData.clear(); - - mVHACD->Release(); + { + LLMutexLock lock(&mDecompDataMutex); + mBoundDecompID = INVALID_DECOMP_ID; + mDecompData.clear(); + } } void LLConvexDecompositionVHACD::genDecomposition(int& decomp) { - int new_decomp_id = static_cast(mDecompData.size()) + 1; - mDecompData[new_decomp_id] = LLDecompData(); - decomp = new_decomp_id; + LLMutexLock lock(&mDecompDataMutex); + + mDecompData[mNextDecompID] = std::make_shared(); + decomp = mNextDecompID; + + ++mNextDecompID; // Increment decomposition ID. Never reuse to protect downstream consumers from misuse } void LLConvexDecompositionVHACD::deleteDecomposition(int decomp) { + LLMutexLock lock(&mDecompDataMutex); + auto iter = mDecompData.find(decomp); if (iter != mDecompData.end()) { - if (mBoundDecomp == &iter->second) + if (mBoundDecompID == decomp) { - mBoundDecomp = nullptr; + mBoundDecompID = INVALID_DECOMP_ID; } mDecompData.erase(iter); } @@ -234,29 +237,48 @@ void LLConvexDecompositionVHACD::deleteDecomposition(int decomp) void LLConvexDecompositionVHACD::bindDecomposition(int decomp) { - auto iter = mDecompData.find(decomp); - if (iter != mDecompData.end()) + LLMutexLock lock(&mDecompDataMutex); + + if (mDecompData.contains(decomp)) { - mBoundDecomp = &iter->second; + mBoundDecompID = decomp; } else { LL_WARNS() << "Failed to bind unknown decomposition: " << decomp << LL_ENDL; - mBoundDecomp = nullptr; + mBoundDecompID = INVALID_DECOMP_ID; } } +LLConvexDecompositionVHACD::data_ptr_t LLConvexDecompositionVHACD::getBoundDecomp() +{ + data_ptr_t bound_decomp; + { + LLMutexLock lock(&mDecompDataMutex); + auto it = mDecompData.find(mBoundDecompID); + if (it != mDecompData.end()) + { + bound_decomp = it->second; // Take a copy of the shared_ptr to avoid potential deletion + } + } + return bound_decomp; +} + LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, float val) { - if (name == std::string("Num Hulls")) + LLMutexLock lock(&mParamsMutex); + + using namespace std::literals; + + if (name == "Num Hulls"sv) { mVHACDParameters.m_maxConvexHulls = llclamp(ll_round(val), 1, MAX_HULLS); } - else if (name == std::string("Num Vertices")) + else if (name == "Num Vertices"sv) { mVHACDParameters.m_maxNumVerticesPerCH = llclamp(ll_round(val), 3, MAX_VERTICES_PER_HULL); } - else if (name == std::string("Error Tolerance")) + else if (name == "Error Tolerance"sv) { mVHACDParameters.m_minimumVolumePercentErrorAllowed = val; } @@ -270,11 +292,15 @@ LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, bool val) LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, int val) { - if (name == std::string("Fill Mode")) + LLMutexLock lock(&mParamsMutex); + + using namespace std::literals; + + if (name == "Fill Mode"sv) { mVHACDParameters.m_fillMode = (VHACD::FillMode)val; } - else if (name == std::string("Voxel Resolution")) + else if (name == "Voxel Resolution"sv) { mVHACDParameters.m_resolution = val; } @@ -283,19 +309,21 @@ LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, int val) LLCDResult LLConvexDecompositionVHACD::setMeshData( const LLCDMeshData* data, bool vertex_based ) { - if (!mBoundDecomp) + data_ptr_t bound_decomp = getBoundDecomp(); + if (!bound_decomp) { return LLCD_NULL_PTR; } - return mBoundDecomp->mSourceMesh.from(data, vertex_based); + return bound_decomp->mSourceMesh.from(data, vertex_based); } LLCDResult LLConvexDecompositionVHACD::registerCallback(int stage, llcdCallbackFunc callback ) { if (stage == 0) { - mVHACDCallback.setCallbackFunc(callback); + LLMutexLock lock(&mParamsMutex); + mCurrentCallbackFunc = callback; return LLCD_OK; } else @@ -306,44 +334,68 @@ LLCDResult LLConvexDecompositionVHACD::registerCallback(int stage, llcdCallbackF LLCDResult LLConvexDecompositionVHACD::executeStage(int stage) { - if (!mBoundDecomp) + if (stage != 0) + { + return LLCD_INVALID_STAGE; + } + + data_ptr_t bound_decomp = getBoundDecomp(); + if (!bound_decomp) { return LLCD_NULL_PTR; } - if (stage != 0) + bound_decomp->mDecomposedHulls.clear(); + + const auto& decomp_mesh = bound_decomp->mSourceMesh; + + VHACDCallback callbacks; + VHACD::IVHACD::Parameters current_params; { - return LLCD_INVALID_STAGE; + LLMutexLock lock(&mParamsMutex); + + current_params = mVHACDParameters; + callbacks.setCallbackFunc(mCurrentCallbackFunc); + } + current_params.m_callback = &callbacks; + + auto vhacd_impl = VHACD::CreateVHACD(); + if (!vhacd_impl) + { + LL_WARNS() << "Failed to create VHACD instance" << LL_ENDL; + return LLCD_NULL_PTR; } - mBoundDecomp->mDecomposedHulls.clear(); - const auto& decomp_mesh = mBoundDecomp->mSourceMesh; - if (!mVHACD->Compute((const double* const)decomp_mesh.mVertices.data(), static_cast(decomp_mesh.mVertices.size()), (const uint32_t* const)decomp_mesh.mIndices.data(), static_cast(decomp_mesh.mIndices.size()), mVHACDParameters)) + if (!vhacd_impl->Compute((const double*)decomp_mesh.mVertices.data(), static_cast(decomp_mesh.mVertices.size()), + (const uint32_t*)decomp_mesh.mIndices.data(), static_cast(decomp_mesh.mIndices.size()), + current_params)) { + vhacd_impl->Release(); return LLCD_INVALID_HULL_DATA; } - uint32_t num_nulls = mVHACD->GetNConvexHulls(); - if (num_nulls == 0) + uint32_t num_convex_hulls = vhacd_impl->GetNConvexHulls(); + if (num_convex_hulls == 0) { + vhacd_impl->Release(); return LLCD_INVALID_HULL_DATA; } - for (uint32_t i = 0; num_nulls > i; ++i) + for (uint32_t i = 0; num_convex_hulls > i; ++i) { VHACD::IVHACD::ConvexHull ch; - if (!mVHACD->GetConvexHull(i, ch)) + if (!vhacd_impl->GetConvexHull(i, ch)) continue; LLConvexMesh out_mesh; out_mesh.setVertices(ch.m_points); out_mesh.setIndices(ch.m_triangles); - mBoundDecomp->mDecomposedHulls.push_back(std::move(out_mesh)); + bound_decomp->mDecomposedHulls.push_back(std::move(out_mesh)); } - mVHACD->Clean(); + vhacd_impl->Release(); return LLCD_OK; } @@ -351,19 +403,21 @@ LLCDResult LLConvexDecompositionVHACD::executeStage(int stage) LLCDResult LLConvexDecompositionVHACD::buildSingleHull() { LL_INFOS() << "Building single hull mesh" << LL_ENDL; - if (!mBoundDecomp || mBoundDecomp->mSourceMesh.mVertices.empty()) + + data_ptr_t bound_decomp = getBoundDecomp(); + if (!bound_decomp || bound_decomp->mSourceMesh.mVertices.empty()) { return LLCD_NULL_PTR; } - mBoundDecomp->mSingleHullMesh.clear(); + bound_decomp->mSingleHullMesh.clear(); VHACD::QuickHull quickhull; - uint32_t num_tris = quickhull.ComputeConvexHull(mBoundDecomp->mSourceMesh.mVertices, MAX_VERTICES_PER_HULL); + uint32_t num_tris = quickhull.ComputeConvexHull(bound_decomp->mSourceMesh.mVertices, MAX_VERTICES_PER_HULL); if (num_tris > 0) { - mBoundDecomp->mSingleHullMesh.setVertices(quickhull.GetVertices()); - mBoundDecomp->mSingleHullMesh.setIndices(quickhull.GetIndices()); + bound_decomp->mSingleHullMesh.setVertices(quickhull.GetVertices()); + bound_decomp->mSingleHullMesh.setIndices(quickhull.GetIndices()); return LLCD_OK; } @@ -373,29 +427,31 @@ LLCDResult LLConvexDecompositionVHACD::buildSingleHull() int LLConvexDecompositionVHACD::getNumHullsFromStage(int stage) { - if (!mBoundDecomp || stage != 0) + data_ptr_t bound_decomp = getBoundDecomp(); + if (!bound_decomp || stage != 0) { return 0; } - return narrow(mBoundDecomp->mDecomposedHulls.size()); + return narrow(bound_decomp->mDecomposedHulls.size()); } LLCDResult LLConvexDecompositionVHACD::getSingleHull( LLCDHull* hullOut ) { memset( hullOut, 0, sizeof(LLCDHull) ); - if (!mBoundDecomp) + data_ptr_t bound_decomp = getBoundDecomp(); + if (!bound_decomp) { return LLCD_NULL_PTR; } - if (mBoundDecomp->mSingleHullMesh.vertices.empty()) + if (bound_decomp->mSingleHullMesh.vertices.empty()) { return LLCD_INVALID_HULL_DATA; } - mBoundDecomp->mSingleHullMesh.to(hullOut); + bound_decomp->mSingleHullMesh.to(hullOut); return LLCD_OK; } @@ -403,7 +459,8 @@ LLCDResult LLConvexDecompositionVHACD::getHullFromStage( int stage, int hull, LL { memset( hullOut, 0, sizeof(LLCDHull) ); - if (!mBoundDecomp) + data_ptr_t bound_decomp = getBoundDecomp(); + if (!bound_decomp) { return LLCD_NULL_PTR; } @@ -413,19 +470,21 @@ LLCDResult LLConvexDecompositionVHACD::getHullFromStage( int stage, int hull, LL return LLCD_INVALID_STAGE; } - if (mBoundDecomp->mDecomposedHulls.empty() || mBoundDecomp->mDecomposedHulls.size() <= hull) + if (bound_decomp->mDecomposedHulls.empty() || S32(bound_decomp->mDecomposedHulls.size()) <= hull) { return LLCD_REQUEST_OUT_OF_RANGE; } - mBoundDecomp->mDecomposedHulls[hull].to(hullOut); + bound_decomp->mDecomposedHulls[hull].to(hullOut); return LLCD_OK; } LLCDResult LLConvexDecompositionVHACD::getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut ) { memset( meshDataOut, 0, sizeof(LLCDMeshData)); - if (!mBoundDecomp) + + data_ptr_t bound_decomp = getBoundDecomp(); + if (!bound_decomp) { return LLCD_NULL_PTR; } @@ -435,12 +494,12 @@ LLCDResult LLConvexDecompositionVHACD::getMeshFromStage( int stage, int hull, LL return LLCD_INVALID_STAGE; } - if (mBoundDecomp->mDecomposedHulls.empty() || mBoundDecomp->mDecomposedHulls.size() <= hull) + if (bound_decomp->mDecomposedHulls.empty() || S32(bound_decomp->mDecomposedHulls.size()) <= hull) { return LLCD_REQUEST_OUT_OF_RANGE; } - mBoundDecomp->mDecomposedHulls[hull].to(meshDataOut); + bound_decomp->mDecomposedHulls[hull].to(meshDataOut); return LLCD_OK; } diff --git a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h index 675356629c4..27c867704e5 100644 --- a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h +++ b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h @@ -31,6 +31,7 @@ #include "llconvexdecomposition.h" #include "llsingleton.h" #include "llmath.h" +#include "llmutex.h" #include @@ -323,14 +324,25 @@ class LLConvexDecompositionVHACD : public LLSimpleton mDecomposedHulls; }; - std::unordered_map mDecompData; + using data_ptr_t = std::shared_ptr; - LLDecompData* mBoundDecomp = nullptr; + data_ptr_t getBoundDecomp(); + + // MUST lock before accessing mDecompData mBoundDecompID or mNextDecompID + LLMutex mDecompDataMutex; + + static constexpr int INVALID_DECOMP_ID = -1; + + int mBoundDecompID = INVALID_DECOMP_ID; + int mNextDecompID = 0; // Only for use inside genDecomposition. + + std::unordered_map mDecompData; - VHACD::IVHACD* mVHACD = nullptr; - VHACDCallback mVHACDCallback; VHACDLogger mVHACDLogger; + + LLMutex mParamsMutex; VHACD::IVHACD::Parameters mVHACDParameters; + llcdCallbackFunc mCurrentCallbackFunc; LLConvexMesh mMeshFromHullData; LLConvexMesh mSingleHullMeshFromMeshData; diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index 930222e3db8..764ab222ad2 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -214,7 +214,7 @@ std::string LLGLTFMaterial::asJSON(bool prettyprint) const // to WriteGltfSceneToStream in the viewer. gltf.WriteGltfSceneToStream(&model_out, str, prettyprint, false); - return str.str(); + return std::move(str).str(); } void LLGLTFMaterial::setFromModel(const tinygltf::Model& model, S32 mat_index) @@ -924,6 +924,34 @@ void LLGLTFMaterial::updateTextureTracking() // for material overrides editor will set it } +// Test cases: +// Case 1. +// Input: scale 1.0,1.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation 0.349066; +// Expected output: scale 1.0,1.0; Offset horizontal 0.201, Offset vertical -0.141 Rotation -0.349066; +// Case 2. +// Input: scale 1.0,1.0; Offset horizontal 0.5, Offset vertical 0.1 Rotation 0; +// Expected output: scale 1.0,1.0; Offset horizontal 0.5, Offset vertical -0.1 Rotation -0; +// Case 3. +// Input: scale 1.0,1.0; Offset horizontal 0.1, Offset vertical 0.2 Rotation 0.349066; +// Expected output: scale 1.0,1.0; Offset horizontal 0.295, Offset vertical -0.345 Rotation -0.349066; +// Case 4. +// Input: scale 1.0,1.0; Offset horizontal 0.5, Offset vertical 0.0 Rotation 0.349066; +// Expected output: scale 1.0,1.0; Offset horizontal 0.701, Offset vertical -0.141 Rotation -0.349066; +// Case 5. +// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation -1.57079637 +// Expected output: scale 15.0,10.0; Offset horizontal 7.5, Offset vertical -4.0 Rotation 1.57079637; +// Case 6. +// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation 0 +// Expected output: scale 10.0,15.0; Offset horizontal 0.5, Offset vertical .0 Rotation 0; +// Case 7. +// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation -0.785398163 +// Expected output: scale 12.74,12.74; Offset horizontal 0.5, Offset vertical .0 Rotation 0.785398163; +// +// Legacy offsets are right to left and top to bottom. +// PBR offsets are right to left and bottom to top. +// +// Legacy rotation is relative to face's center counter clockwise, +// PBR rotation is relative to top-left corner, clockwise void LLGLTFMaterial::convertTextureTransformToPBR( F32 tex_scale_s, F32 tex_scale_t, @@ -934,23 +962,108 @@ void LLGLTFMaterial::convertTextureTransformToPBR( LLVector2& pbr_offset, F32& pbr_rotation) { - pbr_scale.set(tex_scale_s, tex_scale_t); - pbr_rotation = -(tex_rotation) / 2.f; - const F32 adjusted_offset_s = tex_offset_s; - const F32 adjusted_offset_t = -tex_offset_t; - F32 center_adjust_s = 0.5f * (1.0f - tex_scale_s); - F32 center_adjust_t = 0.5f * (1.0f - tex_scale_t); + // Legacy is counter-clockwise, PBR is clockwise + pbr_rotation = -tex_rotation; + + // Center of the tile + const F32 center_s = 0.5f; + const F32 center_t = 0.5f; + + // Calculate the rotated scale + F32 cos_rot = cosf(tex_rotation); + F32 sin_rot = sinf(tex_rotation); + F32 cos_sq = cos_rot * cos_rot; + F32 sin_sq = sin_rot * sin_rot; + + // GLTF scale doesn't match legacy scaling when rotation is applied. + // Legacy applies scale then rotation, which allows for planar aligment + // withoutn deformations, but gltf rotates first, so when scale gets + // aplied image gets deformed by rotation. + // It appears to be imposible to properly match legacy scale, so this + // is an approximation that at least matches at 0, 90, 180, 270 degree + // rotations, and is close enough at angles like 45. + pbr_scale.mV[VX] = tex_scale_s * cos_sq + tex_scale_t * sin_sq; + pbr_scale.mV[VY] = tex_scale_s * sin_sq + tex_scale_t * cos_sq; + + // Center adjustment for scale + F32 center_adjust_s = 0.5f * (1.0f - pbr_scale.mV[VX]); + F32 center_adjust_t = 0.5f * (1.0f - pbr_scale.mV[VY]); + + // 2. Offset from center + F32 pos_s = center_adjust_s - center_s; + F32 pos_t = center_adjust_t - center_t; + + // 3. Rotate around center (clockwise, as per GLTF spec) + F32 c = cosf(pbr_rotation); + F32 s = sinf(pbr_rotation); + F32 rot_s = pos_s * c + pos_t * s; + F32 rot_t = -pos_s * s + pos_t * c; + + // 4. Move back to top-left and apply offset + pbr_offset.set(rot_s + center_s + tex_offset_s, rot_t + center_t - tex_offset_t); +} + +// Convert PBR transform values back to legacy TE transform values. +// This is the reverse of convertTextureTransformToPBR. +void LLGLTFMaterial::convertPBRTransformToTexture( + const LLVector2& pbr_scale, + const LLVector2& pbr_offset, + F32 pbr_rotation, + F32& tex_scale_s, + F32& tex_scale_t, + F32& tex_offset_s, + F32& tex_offset_t, + F32& tex_rotation) +{ + tex_rotation = -pbr_rotation; - if (pbr_rotation != 0.0f) + // Reverse the scale transformation + // From: pbr_s = tex_s * cos² + tex_t * sin² + // pbr_t = tex_s * sin² + tex_t * cos² + // Solve for tex_s and tex_t + F32 cos_rot = cosf(tex_rotation); + F32 sin_rot = sinf(tex_rotation); + F32 cos_sq = cos_rot * cos_rot; + F32 sin_sq = sin_rot * sin_rot; + + F32 denom = cos_sq * cos_sq - sin_sq * sin_sq; + + if (fabsf(denom) < 0.0001f) // Near 45 degrees (cos²≈sin²≈0.5) + { + // At 45°: both scales contribute equally + // pbr_s = pbr_t = (tex_s + tex_t) / 2 + // So: tex_s + tex_t = 2 * pbr_avg + // Use the average and assume symmetric scaling + tex_scale_s = tex_scale_t = (pbr_scale.mV[VX] + pbr_scale.mV[VY]) / 2.f; + } + else { - const F32 c = cosf(pbr_rotation); - const F32 s = sinf(pbr_rotation); - const F32 tmp_s = center_adjust_s * c - center_adjust_t * s; - const F32 tmp_t = center_adjust_s * s + center_adjust_t * c; - center_adjust_s = tmp_s; - center_adjust_t = tmp_t; + // Solve the 2x2 system: + // pbr_s * cos² - pbr_t * sin² = tex_s * (cos⁴ - sin⁴) + // pbr_t * cos² - pbr_s * sin² = tex_t * (cos⁴ - sin⁴) + tex_scale_s = (pbr_scale.mV[VX] * cos_sq - pbr_scale.mV[VY] * sin_sq) / denom; + tex_scale_t = (pbr_scale.mV[VY] * cos_sq - pbr_scale.mV[VX] * sin_sq) / denom; } - pbr_offset.set(adjusted_offset_s + center_adjust_s, - adjusted_offset_t + center_adjust_t); + // Center of the tile + const F32 center_s = 0.5f; + const F32 center_t = 0.5f; + + // Center adjustment for scale + F32 center_adjust_s = 0.5f * (1.0f - pbr_scale.mV[VX]); + F32 center_adjust_t = 0.5f * (1.0f - pbr_scale.mV[VY]); + + // 2. Offset from center + F32 pos_s = center_adjust_s - center_s; + F32 pos_t = center_adjust_t - center_t; + + // 3. Rotate around center (clockwise, as per GLTF spec) + F32 c = cosf(pbr_rotation); + F32 s = sinf(pbr_rotation); + F32 rot_s = pos_s * c + pos_t * s; + F32 rot_t = -pos_s * s + pos_t * c; + + // 3. Recover legacy offset + tex_offset_s = pbr_offset.mV[0] - rot_s - center_s; + tex_offset_t = -(pbr_offset.mV[1] - rot_t - center_t); } diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index 8d45cb61851..c37062e7d3d 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -222,6 +222,14 @@ class LLGLTFMaterial : public LLRefCount LLVector2& pbr_scale, LLVector2& pbr_offset, F32& pbr_rotation); + + // Convert PBR transform values to legacy TE transform values. + static void convertPBRTransformToTexture(const LLVector2& pbr_scale, + const LLVector2& pbr_offset, + F32 pbr_rotation, + F32& tex_scale_s, F32& tex_scale_t, + F32& tex_offset_s, F32& tex_offset_t, + F32& tex_rotation); protected: static LLVector2 vec2FromJson(const std::map& object, const char* key, const LLVector2& default_value); static F32 floatFromJson(const std::map& object, const char* key, const F32 default_value); diff --git a/indra/llprimitive/llmaterialid.h b/indra/llprimitive/llmaterialid.h index bd6256d9619..41dd5a87109 100644 --- a/indra/llprimitive/llmaterialid.h +++ b/indra/llprimitive/llmaterialid.h @@ -67,15 +67,11 @@ class LLMaterialID static const LLMaterialID null; - // Returns a 64 bits digest of the material Id, by XORing its two 64 bits - // long words. HB - inline U64 getDigest64() const - { - U64* tmp = (U64*)mID; - return tmp[0] ^ tmp[1]; - } - private: + // definitions follow class + friend std::hash; + friend size_t hash_value(const LLMaterialID&) noexcept; + void parseFromBinary(const LLSD::Binary& pMaterialID); void copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID); int compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const; @@ -90,15 +86,27 @@ namespace std { inline size_t operator()(const LLMaterialID& id) const noexcept { - return (size_t)id.getDigest64(); + size_t h = 0; + // Golden ratio hash with avalanche mixing + // Process 8 bytes at a time by manually constructing 64-bit values + // Shift by 31: mixes upper half into lower half for better bit distribution + // Shift by 47: ensures highest bits influence final hash output + for (int i = 0; i < MATERIAL_ID_SIZE; i += 8) { + size_t chunk = (size_t)id.mID[i] | ((size_t)id.mID[i + 1] << 8) | + ((size_t)id.mID[i+2] << 16) | ((size_t)id.mID[i+3] << 24) | + ((size_t)id.mID[i+4] << 32) | ((size_t)id.mID[i+5] << 40) | + ((size_t)id.mID[i + 6] << 48) | ((size_t)id.mID[i + 7] << 56); + h ^= (chunk * 0x9e3779b97f4a7c15ULL) ^ (h >> 31) ^ (h >> 47); + } + return h; } }; } -// For use with boost containers. +// For use with boost::container_hash inline size_t hash_value(const LLMaterialID& id) noexcept { - return (size_t)id.getDigest64(); + return std::hash{}(id); } #endif // LL_LLMATERIALID_H diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 31bc76344c3..c3e3e19ee94 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -109,11 +109,12 @@ class LLNetworkData PARAMS_EXTENDED_MESH = 0x70, PARAMS_RENDER_MATERIAL = 0x80, PARAMS_REFLECTION_PROBE = 0x90, + PARAMS_MAX = PARAMS_REFLECTION_PROBE, }; public: U16 mType; - virtual ~LLNetworkData() {}; + virtual ~LLNetworkData() = default; virtual bool pack(LLDataPacker &dp) const = 0; virtual bool unpack(LLDataPacker &dp) = 0; virtual bool operator==(const LLNetworkData& data) const = 0; @@ -319,7 +320,7 @@ class LLSculptParams : public LLNetworkData bool fromLLSD(LLSD& sd); void setSculptTexture(const LLUUID& texture_id, U8 sculpt_type); - LLUUID getSculptTexture() const { return mSculptTexture; } + const LLUUID& getSculptTexture() const { return mSculptTexture; } U8 getSculptType() const { return mSculptType; } }; @@ -340,10 +341,10 @@ class LLLightImageParams : public LLNetworkData bool fromLLSD(LLSD& sd); void setLightTexture(const LLUUID& id) { mLightTexture = id; } - LLUUID getLightTexture() const { return mLightTexture; } + const LLUUID& getLightTexture() const { return mLightTexture; } bool isLightSpotlight() const { return mLightTexture.notNull(); } void setParams(const LLVector3& params) { mParams = params; } - LLVector3 getParams() const { return mParams; } + const LLVector3& getParams() const { return mParams; } }; diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h index a9b3a944ee2..f7600e40a31 100644 --- a/indra/llrender/llfontfreetype.h +++ b/indra/llrender/llfontfreetype.h @@ -27,13 +27,14 @@ #ifndef LL_LLFONTFREETYPE_H #define LL_LLFONTFREETYPE_H -#include #include "llpointer.h" #include "llstl.h" #include "llimagegl.h" #include "llfontbitmapcache.h" +#include + // Hack. FT_Face is just a typedef for a pointer to a struct, // but there's no simple forward declarations file for FreeType, // and the main include file is 200K. @@ -184,7 +185,7 @@ class LLFontFreetype : public LLRefCount fallback_font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars) // *NOTE: the same glyph can be present with multiple representations (but the pointer is always unique) - typedef boost::unordered_multimap char_glyph_info_map_t; + typedef std::unordered_multimap char_glyph_info_map_t; mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap mutable LLFontBitmapCache* mFontBitmapCachep; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index d13b98e2747..4584ed1d865 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -2376,7 +2376,7 @@ void clear_glerror() // // Static members -boost::unordered_map LLGLState::sStateMap; +std::unordered_map LLGLState::sStateMap; GLboolean LLGLDepthTest::sDepthEnabled = GL_FALSE; // OpenGL default GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default @@ -2419,7 +2419,7 @@ void LLGLState::resetTextureStates() void LLGLState::dumpStates() { LL_INFOS("RenderState") << "GL States:" << LL_ENDL; - for (boost::unordered_map::iterator iter = sStateMap.begin(); + for (std::unordered_map::iterator iter = sStateMap.begin(); iter != sStateMap.end(); ++iter) { LL_INFOS("RenderState") << llformat(" 0x%04x : %s",(S32)iter->first,iter->second?"true":"false") << LL_ENDL; @@ -2451,7 +2451,7 @@ void LLGLState::checkStates(GLboolean writeAlpha) //llassert_always(colorMask[2]); // llassert_always(colorMask[3] == writeAlpha); - for (boost::unordered_map::iterator iter = sStateMap.begin(); + for (std::unordered_map::iterator iter = sStateMap.begin(); iter != sStateMap.end(); ++iter) { LLGLenum state = iter->first; diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index d19825d9ca6..e1ab2a49e6d 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include "llerror.h" @@ -246,7 +246,7 @@ class LLGLState static void checkStates(GLboolean writeAlpha = GL_TRUE); protected: - static boost::unordered_map sStateMap; + static std::unordered_map sStateMap; public: enum { CURRENT_STATE = -2, DISABLED_STATE = 0, ENABLED_STATE = 1 }; diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 97ea6f67bd8..4a3d32c7ffc 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -2189,7 +2189,7 @@ void LLImageGL::calcAlphaChannelOffsetAndStride() void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) { - if(sSkipAnalyzeAlpha || !mNeedsAlphaAndPickMask) + if(!data_in || sSkipAnalyzeAlpha || !mNeedsAlphaAndPickMask) { return ; } diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 57be8570afb..1a3a499b201 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -1774,25 +1774,64 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) return; } - if (mUIOffset.empty()) + LLVector4a vert(x, y, z); + transform(vert); + mVerticesp[mCount] = vert; + + mCount++; + mVerticesp[mCount] = mVerticesp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; +} + +void LLRender::transform(LLVector3& vert) +{ + if (!mUIOffset.empty()) { - mVerticesp[mCount].set(x,y,z); + vert += LLVector3(mUIOffset.back().getF32ptr()); + vert *= LLVector3(mUIScale.back().getF32ptr()); } - else +} + +void LLRender::transform(LLVector4a& vert) +{ + if (!mUIOffset.empty()) { - LLVector4a vert(x, y, z); vert.add(mUIOffset.back()); vert.mul(mUIScale.back()); - mVerticesp[mCount] = vert; } +} - mCount++; - mVerticesp[mCount] = mVerticesp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; +void LLRender::untransform(LLVector3& vert) +{ + if (!mUIOffset.empty()) + { + vert /= LLVector3(mUIScale.back().getF32ptr()); + vert -= LLVector3(mUIOffset.back().getF32ptr()); + } +} + +void LLRender::batchTransform(LLVector4a* verts, U32 vert_count) +{ + if (!mUIOffset.empty()) + { + const LLVector4a& offset = mUIOffset.back(); + const LLVector4a& scale = mUIScale.back(); + + for (U32 i = 0; i < vert_count; ++i) + { + verts[i].add(offset); + verts[i].mul(scale); + } + } +} + +void LLRender::vertexBatchPreTransformed(const std::vector& verts) +{ + vertexBatchPreTransformed(verts.data(), narrow(verts.size())); } -void LLRender::vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count) +void LLRender::vertexBatchPreTransformed(const LLVector4a* verts, S32 vert_count) { if (mCount + vert_count > 4094) { @@ -1813,7 +1852,7 @@ void LLRender::vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count) mVerticesp[mCount] = mVerticesp[mCount-1]; } -void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count) +void LLRender::vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, S32 vert_count) { if (mCount + vert_count > 4094) { @@ -1837,7 +1876,7 @@ void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 } } -void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count) +void LLRender::vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, const LLColor4U* colors, S32 vert_count) { if (mCount + vert_count > 4094) { diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 0801c12fb4c..be8539433cb 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -450,9 +450,16 @@ class LLRender void diffuseColor4ubv(const U8* c); void diffuseColor4ub(U8 r, U8 g, U8 b, U8 a); - void vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count); - void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count); - void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U*, S32 vert_count); + void transform(LLVector3& vert); + void transform(LLVector4a& vert); + void untransform(LLVector3& vert); + + void batchTransform(LLVector4a* verts, U32 vert_count); + + void vertexBatchPreTransformed(const std::vector& verts); + void vertexBatchPreTransformed(const LLVector4a* verts, S32 vert_count); + void vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, S32 vert_count); + void vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, const LLColor4U*, S32 vert_count); void setColorMask(bool writeColor, bool writeAlpha); void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha); 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/llui/llcallbackmap.h b/indra/llui/llcallbackmap.h index 3115606d91e..69b80db1e8d 100644 --- a/indra/llui/llcallbackmap.h +++ b/indra/llui/llcallbackmap.h @@ -27,9 +27,11 @@ #ifndef LLCALLBACKMAP_H #define LLCALLBACKMAP_H -#include +#include "llstl.h" + #include #include +#include class LLCallbackMap { @@ -37,7 +39,7 @@ class LLCallbackMap // callback definition. typedef std::function callback_t; - typedef std::map map_t; + typedef std::unordered_map map_t; typedef map_t::iterator map_iter_t; typedef map_t::const_iterator map_const_iter_t; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 52a5e3dbd69..c60253e7fe8 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -239,7 +239,7 @@ void LLFloater::initClass() } // defaults for floater param block pulled from widgets/floater.xml -static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(&typeid(LLFloater::Params), "floater"); +static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(typeid(LLFloater::Params), "floater"); LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) : LLPanel(), // intentionally do not pass params here, see initFromParams diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index a818e72f59e..c18495ce715 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -40,9 +40,9 @@ LLFloaterReg::instance_list_t LLFloaterReg::sNullInstanceList; LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap; LLFloaterReg::build_map_t LLFloaterReg::sBuildMap; -std::map> LLFloaterReg::sGroupMap; +LLFloaterReg::group_map_t LLFloaterReg::sGroupMap; bool LLFloaterReg::sBlockShowFloaters = false; -std::set> LLFloaterReg::sAlwaysShowableList; +LLFloaterReg::always_showable_t LLFloaterReg::sAlwaysShowableList; static LLFloaterRegListener sFloaterRegListener; @@ -96,11 +96,8 @@ LLFloater* LLFloaterReg::getLastFloaterCascading() candidate_rect.mTop = 100000; LLFloater* candidate_floater = NULL; - std::map::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end(); - for( ; it != it_end; ++it) + for (const auto& [floater_name, group_name] : sGroupMap) { - const std::string& group_name = it->second; - instance_list_t& instances = sInstanceMap[group_name]; for (LLFloater* inst : instances) @@ -604,17 +601,11 @@ U32 LLFloaterReg::getVisibleFloaterInstanceCount() { U32 count = 0; - std::map::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end(); - for( ; it != it_end; ++it) + for (const auto& [floater_name, group_name] : sGroupMap) { - const std::string& group_name = it->second; - instance_list_t& instances = sInstanceMap[group_name]; - - for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter) + for (LLFloater* inst : instances) { - LLFloater* inst = *iter; - if (inst->getVisible() && !inst->isMinimized()) { count++; diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index 24d1476dda5..71a11b6f425 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -29,9 +29,11 @@ /// llcommon #include "llrect.h" #include "llsd.h" +#include "llstl.h" #include #include +#include //******************************************************* // @@ -51,26 +53,29 @@ class LLFloaterReg // 2) We can change the key of a floater without altering the list. typedef std::list instance_list_t; typedef const instance_list_t const_instance_list_t; - typedef std::map> instance_map_t; + typedef std::unordered_map> instance_map_t; struct BuildData { LLFloaterBuildFunc mFunc; std::string mFile; }; - typedef std::map> build_map_t; + typedef std::unordered_map> build_map_t; private: friend class LLFloaterRegListener; static instance_list_t sNullInstanceList; static instance_map_t sInstanceMap; static build_map_t sBuildMap; - static std::map> sGroupMap; + + using group_map_t = std::unordered_map>; + static group_map_t sGroupMap; static bool sBlockShowFloaters; /** * Defines list of floater names that can be shown despite state of sBlockShowFloaters. */ - static std::set> sAlwaysShowableList; + using always_showable_t = std::unordered_set>; + static always_showable_t sAlwaysShowableList; public: // Registration diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 878f1cb856e..dafbca7433b 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -28,6 +28,7 @@ #include "llflashtimer.h" #include "linden_common.h" +#include "llapp.h" #include "llfolderviewitem.h" #include "llfolderview.h" #include "llfolderviewmodel.h" @@ -1884,6 +1885,11 @@ void LLFolderViewFolder::updateHasFavorites(bool new_childs_value) void LLFolderViewFolder::onIdleUpdateFavorites(void* data) { LLFolderViewFolder* self = reinterpret_cast(data); + if (gDisconnected || !self) + { + return; + } + if (self->mFavoritesDirtyFlags == FAVORITE_CLEANUP) { // parent or child already processed the update, clean the callback @@ -2359,9 +2365,10 @@ bool LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask ) { // navigating is going to destroy views and change children // delay it untill handleDoubleClick processing is complete - doOnIdleOneTime([this]() - { - getViewModelItem()->navigateToFolder(false); + LLPointer view_model_item = getViewModelItem(); + doOnIdleOneTime([view_model_item]() mutable + {; + view_model_item->navigateToFolder(false); }); } return true; diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h index 953963b683a..40a3e439a60 100644 --- a/indra/llui/llfunctorregistry.h +++ b/indra/llui/llfunctorregistry.h @@ -29,8 +29,9 @@ #define LL_LLFUNCTORREGISTRY_H #include -#include +#include +#include "llstring.h" #include "llsd.h" #include "llsingleton.h" @@ -56,7 +57,7 @@ class LLFunctorRegistry : public LLSingleton > public: typedef FUNCTOR_TYPE ResponseFunctor; - typedef typename std::map FunctorMap; + typedef typename std::unordered_map> FunctorMap; bool registerFunctor(const std::string& name, ResponseFunctor f) { diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h index 5892238593e..53b54353247 100644 --- a/indra/llui/llkeywords.h +++ b/indra/llui/llkeywords.h @@ -194,7 +194,7 @@ class LLKeywords token_list_t mLineTokenList; token_list_t mDelimiterTokenList; - typedef std::map> element_attributes_t; + typedef std::unordered_map> element_attributes_t; typedef element_attributes_t::const_iterator attribute_iterator_t; element_attributes_t mAttributes; std::string getAttribute(std::string_view key); diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index b534c8d4e82..ef62666918b 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -122,6 +122,7 @@ LLLineEditor::Params::Params() LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) : LLUICtrl(p), + mDefaultText(p.default_text), mMaxLengthBytes(p.max_length.bytes), mMaxLengthChars(p.max_length.chars), mCursorPos( 0 ), diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 3f762822eeb..6384bfdc5f6 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -202,6 +202,7 @@ class LLLineEditor void setLabel(const LLStringExplicit &new_label) { mLabel = new_label; } const std::string& getLabel() { return mLabel.getString(); } + void setDefaultText() { setText(mDefaultText); } void setText(const LLStringExplicit &new_text); const std::string& getText() const override { return mText.getString(); } @@ -347,6 +348,7 @@ class LLLineEditor LLFontVertexBuffer mFontBufferSelection; LLFontVertexBuffer mFontBufferPostSelection; LLFontVertexBuffer mFontBufferLabel; + std::string mDefaultText; S32 mMaxLengthBytes; // Max length of the UTF8 string in bytes S32 mMaxLengthChars; // Maximum number of characters in the string S32 mCursorPos; // I-beam is just after the mCursorPos-th character. diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 0ffe6cff5ec..56475a2d8d8 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -1424,6 +1424,7 @@ LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelN // this function is called once at construction time, after the object is constructed. void LLNotifications::initSingleton() { + LL_PROFILE_ZONE_SCOPED; loadTemplates(); loadVisibilityRules(); createDefaultChannels(); @@ -1436,6 +1437,8 @@ void LLNotifications::cleanupSingleton() void LLNotifications::createDefaultChannels() { + LL_PROFILE_ZONE_SCOPED; + LL_INFOS("Notifications") << "Generating default notification channels" << LL_ENDL; // now construct the various channels AFTER loading the notifications, // because the history channel is going to rewrite the stored notifications file @@ -1578,6 +1581,8 @@ void addPathIfExists(const std::string& new_path, std::vector& path bool LLNotifications::loadTemplates() { + LL_PROFILE_ZONE_SCOPED; + LL_INFOS("Notifications") << "Reading notifications template" << LL_ENDL; // Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it // output all relevant pathnames instead of just the ones from the most @@ -1663,6 +1668,8 @@ bool LLNotifications::loadTemplates() bool LLNotifications::loadVisibilityRules() { + LL_PROFILE_ZONE_SCOPED; + const std::string xml_filename = "notification_visibility.xml"; // Note that here we're looking for the "en" version, the default // language, rather than the most localized version of this file. diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index d56c459560a..ea1cb7f6384 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -93,6 +93,7 @@ #include "llinitparam.h" #include "llinstancetracker.h" #include "llmortician.h" +#include "llmutex.h" #include "llnotificationptr.h" #include "llpointer.h" #include "llrefcount.h" @@ -945,7 +946,7 @@ class LLNotifications : typedef std::vector TemplateNames; TemplateNames getTemplateNames() const; // returns a list of notification names - typedef std::map> TemplateMap; + typedef std::unordered_map> TemplateMap; TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); } TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); } @@ -991,7 +992,7 @@ class LLNotifications : LLNotificationMap mUniqueNotifications; - typedef std::map> GlobalStringMap; + typedef std::unordered_map> GlobalStringMap; GlobalStringMap mGlobalStrings; bool mIgnoreAllNotifications; diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index fe861dc719c..a928997c7d9 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -250,7 +250,7 @@ class LLPanel : public LLUICtrl, public LLBadgeHolder LLButton* mDefaultBtn; LLUIString mLabel; - typedef std::map> ui_string_map_t; + typedef std::unordered_map> ui_string_map_t; ui_string_map_t mUIStrings; @@ -292,7 +292,7 @@ class LLRegisterPanelClass } private: - typedef std::map< std::string, LLPanelClassCreatorFunc, std::less<>> param_name_map_t; + typedef std::unordered_map> param_name_map_t; param_name_map_t mPanelClassesNames; }; diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp index 2aff434612f..1dbd9f5b0ce 100644 --- a/indra/llui/llradiogroup.cpp +++ b/indra/llui/llradiogroup.cpp @@ -67,7 +67,7 @@ class LLRadioCtrl : public LLCheckBoxCtrl LLSD mPayload; // stores data that this item represents in the radio group }; -static LLWidgetNameRegistry::StaticRegistrar register_radio_item(&typeid(LLRadioGroup::ItemParams), "radio_item"); +static LLWidgetNameRegistry::StaticRegistrar register_radio_item(typeid(LLRadioGroup::ItemParams), "radio_item"); LLRadioGroup::Params::Params() : allow_deselect("allow_deselect"), diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp index 1b4008cff27..5b0d2315c1a 100644 --- a/indra/llui/llrngwriter.cpp +++ b/indra/llui/llrngwriter.cpp @@ -94,7 +94,7 @@ void LLRNGWriter::addDefinition(const std::string& type_name, const LLInitParam: block.inspectBlock(*this); // add includes for all possible children - const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name); + const std::type_index& type = *LLWidgetTypeRegistry::instance().getValue(type_name); const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type); // add include declarations for all valid children diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp index a4510d1fc24..b5ba4667506 100644 --- a/indra/llui/llscrolllistcolumn.cpp +++ b/indra/llui/llscrolllistcolumn.cpp @@ -39,7 +39,7 @@ const S32 MIN_COLUMN_WIDTH = 20; // defaults for LLScrollColumnHeader param block pulled from widgets/scroll_column_header.xml -static LLWidgetNameRegistry::StaticRegistrar sRegisterColumnHeaderParams(&typeid(LLScrollColumnHeader::Params), "scroll_column_header"); +static LLWidgetNameRegistry::StaticRegistrar sRegisterColumnHeaderParams(typeid(LLScrollColumnHeader::Params), "scroll_column_header"); //--------------------------------------------------------------------------- // LLScrollColumnHeader diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index b459c67dade..558ce6a7fd3 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -3185,6 +3185,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS if (cell_p.width.isProvided()) { new_column.width.pixel_width = cell_p.width; + new_column.width.pixel_width.choose(); } addColumn(new_column); columnp = mColumns[column]; diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 5e0985c79cf..48e42d9fc02 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -2202,3 +2202,16 @@ void LLTabContainer::setTabVisibility( LLPanel const *aPanel, bool aVisible ) updateMaxScrollPos(); } + +bool LLTabContainer::getTabVisibility(const LLPanel* panel) const +{ + for (tuple_list_t::const_iterator itr = mTabList.begin(); itr != mTabList.end(); ++itr) + { + LLTabTuple const* pTT = *itr; + if (pTT->mTabPanel == panel) + { + return pTT->mVisible; + } + } + return false; +} diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 4ac7e73d259..cbf56dc653b 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -225,6 +225,7 @@ class LLTabContainer : public LLPanel S32 getMaxTabWidth() const { return mMaxTabWidth; } void setTabVisibility( LLPanel const *aPanel, bool ); + bool getTabVisibility(const LLPanel* panel) const; void startDragAndDropDelayTimer() { mDragAndDropDelayTimer.start(); } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 2079ff17fc2..24ae5c09e98 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -129,7 +129,7 @@ struct LLTextBase::line_end_compare // // register LLTextBase::Params under name "textbase" -static LLWidgetNameRegistry::StaticRegistrar sRegisterTextBaseParams(&typeid(LLTextBase::Params), "textbase"); +static LLWidgetNameRegistry::StaticRegistrar sRegisterTextBaseParams(typeid(LLTextBase::Params), "textbase"); LLTextBase::LineSpacingParams::LineSpacingParams() : multiple("multiple", 1.f), diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index fcdf3782ae7..7689b933741 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -581,7 +581,7 @@ S32 LLTextEditor::indentLine( S32 pos, S32 spaces ) LLWString wtext = getWText(); if (wtext[pos] == ' ') { - delta_spaces += remove( pos, 1, false ); + delta_spaces -= remove( pos, 1, false ); } } } diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index 74f03618cfe..c5b1b5ba1d1 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -129,7 +129,7 @@ void LLToolTipView::drawStickyRect() } // defaults for floater param block pulled from widgets/floater.xml -static LLWidgetNameRegistry::StaticRegistrar sRegisterInspectorParams(&typeid(LLInspector::Params), "inspector"); +static LLWidgetNameRegistry::StaticRegistrar sRegisterInspectorParams(typeid(LLInspector::Params), "inspector"); // // LLToolTip diff --git a/indra/llui/lltrans.h b/indra/llui/lltrans.h index c5d01e6f8da..4dba4c5c3ec 100644 --- a/indra/llui/lltrans.h +++ b/indra/llui/lltrans.h @@ -125,7 +125,7 @@ class LLTrans } private: - typedef std::map> template_map_t; + typedef std::unordered_map> template_map_t; static template_map_t sStringTemplates; static template_map_t sDefaultStringTemplates; static LLStringUtil::format_map_t sDefaultArgs; diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 38d57205560..0056e73cced 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -65,7 +65,6 @@ // for XUIParse #include "llquaternion.h" -#include #include #include @@ -157,6 +156,7 @@ mWindow(NULL), // set later in startup mRootView(NULL), mHelpImpl(NULL) { + LL_PROFILE_ZONE_SCOPED; LLRender2D::createInstance(image_provider); LLSpellChecker::createInstance(); diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 2ef64baaf6f..091e0ab1cf7 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -114,7 +114,7 @@ class LLUI : public LLSimpleton { LOG_CLASS(LLUI); public: - typedef std::map > settings_map_t; + typedef std::unordered_map> settings_map_t; LLUI(const settings_map_t &settings, LLImageProviderInterface* image_provider, diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp index a792cb8103f..7a4f72fe4f5 100644 --- a/indra/llui/lluicolortable.cpp +++ b/indra/llui/lluicolortable.cpp @@ -198,8 +198,8 @@ LLUIColor LLUIColorTable::getColor(std::string_view name, const LLColor4& defaul // update user color, loaded colors are parsed on initialization void LLUIColorTable::setColor(std::string_view name, const LLColor4& color) { - auto it = mUserSetColors.lower_bound(name); - if(it != mUserSetColors.end() && !(mUserSetColors.key_comp()(name, it->first))) + auto it = mUserSetColors.find(name); + if(it != mUserSetColors.end()) { it->second = color; } @@ -330,9 +330,8 @@ void LLUIColorTable::clearTable(string_color_map_t& table) // if the color already exists it changes the color void LLUIColorTable::setColor(std::string_view name, const LLColor4& color, string_color_map_t& table) { - string_color_map_t::iterator it = table.lower_bound(name); - if(it != table.end() - && !(table.key_comp()(name, it->first))) + string_color_map_t::iterator it = table.find(name); + if(it != table.end()) { it->second = color; } diff --git a/indra/llui/lluicolortable.h b/indra/llui/lluicolortable.h index 0c6286e5eb6..aff6f59db66 100644 --- a/indra/llui/lluicolortable.h +++ b/indra/llui/lluicolortable.h @@ -27,7 +27,7 @@ #ifndef LL_LLUICOLORTABLE_H_ #define LL_LLUICOLORTABLE_H_ -#include +#include #include "llinitparam.h" #include "llsingleton.h" @@ -42,7 +42,7 @@ class LLUIColorTable : public LLSingleton LOG_CLASS(LLUIColorTable); // consider using sorted vector, can be much faster - typedef std::map> string_color_map_t; + typedef std::unordered_map> string_color_map_t; public: struct ColorParams : LLInitParam::ChoiceBlock diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index 9abccfd9a0a..33ffc3dfc63 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -253,7 +253,7 @@ const LLInitParam::BaseBlock& get_empty_param_block() // adds a widget and its param block to various registries //static -void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& name) +void LLUICtrlFactory::registerWidget(std::type_index widget_type, std::type_index param_block_type, const std::string& name) { // associate parameter block type with template .xml file std::string* existing_name = LLWidgetNameRegistry::instance().getValue(param_block_type); diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index fc069c078f9..f44b4ba4dcf 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -65,7 +65,7 @@ class LLDefaultChildRegistry : public LLChildRegistry // lookup widget name by type class LLWidgetNameRegistry -: public LLRegistrySingleton +: public LLRegistrySingleton { LLSINGLETON_EMPTY_CTOR(LLWidgetNameRegistry); }; @@ -74,7 +74,7 @@ class LLWidgetNameRegistry // this is used for schema generation //typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)(); //class LLDefaultParamBlockRegistry -//: public LLRegistrySingleton +//: public LLRegistrySingleton //{ // LLSINGLETON(LLDefaultParamBlockRegistry); //}; @@ -202,7 +202,7 @@ class LLUICtrlFactory : public LLSingleton static void copyName(LLXMLNodePtr src, LLXMLNodePtr dest); // helper function for adding widget type info to various registries - static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag); + static void registerWidget(std::type_index widget_type, std::type_index param_block_type, const std::string& tag); static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block); @@ -290,7 +290,7 @@ template LLUICtrlFactory::ParamDefaults::ParamDefaults() { // look up template file for this param block... - const std::string* param_block_tag = LLWidgetNameRegistry::instance().getValue(&typeid(PARAM_BLOCK)); + const std::string* param_block_tag = LLWidgetNameRegistry::instance().getValue(typeid(PARAM_BLOCK)); if (param_block_tag) { // ...and if it exists, back fill values using the most specific template first PARAM_BLOCK params; @@ -314,12 +314,12 @@ LLChildRegistry::Register::Register(const char* tag, LLWidgetCreator : LLChildRegistry::StaticRegistrar(tag, func == nullptr ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder : func) { // add this widget to various registries - LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), tag); + LLUICtrlFactory::instance().registerWidget(typeid(T), typeid(typename T::Params), tag); // since registry_t depends on T, do this in line here // TODO: uncomment this for schema generation //typedef typename T::child_registry_t registry_t; - //LLChildRegistryRegistry::instance().defaultRegistrar().add(&typeid(T), registry_t::instance()); + //LLChildRegistryRegistry::instance().defaultRegistrar().add(typeid(T), registry_t::instance()); } #endif //LLUICTRLFACTORY_H diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp index 8fd85a89a18..71ce2afdbd9 100644 --- a/indra/llui/llxuiparser.cpp +++ b/indra/llui/llxuiparser.cpp @@ -602,7 +602,7 @@ void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& p LLXSDWriter::writeXSD(type_name, root_nodep, block, "http://www.lindenlab.com/xui"); // add includes for all possible children - const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name); + const std::type_index& type = *LLWidgetTypeRegistry::instance().getValue(type_name); const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type); // add choices for valid children @@ -1459,7 +1459,7 @@ void LLSimpleXUIParser::characterDataHandler(void *userData, const char *s, int void LLSimpleXUIParser::characterData(const char *s, int len) { - mTextContents += std::string(s, len); + mTextContents.append(s, len); } void LLSimpleXUIParser::startElement(const char *name, const char **atts) @@ -1480,24 +1480,24 @@ void LLSimpleXUIParser::startElement(const char *name, const char **atts) mOutputStack.back().second++; S32 num_tokens_pushed = 0; - std::string child_name(name); + std::string_view child_name(name); if (mOutputStack.back().second == 1) { // root node for this block - mScope.push_back(child_name); + mScope.emplace_back(child_name); } else { // compound attribute if (child_name.find(".") == std::string::npos) { - mNameStack.push_back(std::make_pair(child_name, true)); + mNameStack.emplace_back(child_name, true); num_tokens_pushed++; - mScope.push_back(child_name); + mScope.emplace_back(child_name); } else { // parse out "dotted" name into individual tokens - tokenizer name_tokens(child_name, sep); + tokenizer name_tokens(std::string(child_name), sep); tokenizer::iterator name_token_it = name_tokens.begin(); if(name_token_it == name_tokens.end()) @@ -1603,8 +1603,8 @@ bool LLSimpleXUIParser::processText() LLStringUtil::trim(mTextContents); if (!mTextContents.empty()) { - mNameStack.push_back(std::make_pair(std::string("value"), true)); - mCurAttributeValueBegin = mTextContents.c_str(); + mNameStack.emplace_back("value", true); + mCurAttributeValueBegin = std::move(mTextContents); mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); mNameStack.pop_back(); } @@ -1648,12 +1648,12 @@ bool LLSimpleXUIParser::readFlag(Parser& parser, void* val_ptr) bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr) { LLSimpleXUIParser& self = static_cast(parser); - if (!strcmp(self.mCurAttributeValueBegin, "true")) + if (!strcmp(self.mCurAttributeValueBegin.c_str(), "true")) { *((bool*)val_ptr) = true; return true; } - else if (!strcmp(self.mCurAttributeValueBegin, "false")) + else if (!strcmp(self.mCurAttributeValueBegin.c_str(), "false")) { *((bool*)val_ptr) = false; return true; @@ -1665,56 +1665,56 @@ bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr) bool LLSimpleXUIParser::readStringValue(Parser& parser, void* val_ptr) { LLSimpleXUIParser& self = static_cast(parser); - *((std::string*)val_ptr) = self.mCurAttributeValueBegin; + *((std::string*)val_ptr) = std::move(self.mCurAttributeValueBegin); return true; } bool LLSimpleXUIParser::readU8Value(Parser& parser, void* val_ptr) { LLSimpleXUIParser& self = static_cast(parser); - return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full; + return parse(self.mCurAttributeValueBegin.c_str(), uint_p[assign_a(*(U8*)val_ptr)]).full; } bool LLSimpleXUIParser::readS8Value(Parser& parser, void* val_ptr) { LLSimpleXUIParser& self = static_cast(parser); - return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full; + return parse(self.mCurAttributeValueBegin.c_str(), int_p[assign_a(*(S8*)val_ptr)]).full; } bool LLSimpleXUIParser::readU16Value(Parser& parser, void* val_ptr) { LLSimpleXUIParser& self = static_cast(parser); - return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full; + return parse(self.mCurAttributeValueBegin.c_str(), uint_p[assign_a(*(U16*)val_ptr)]).full; } bool LLSimpleXUIParser::readS16Value(Parser& parser, void* val_ptr) { LLSimpleXUIParser& self = static_cast(parser); - return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full; + return parse(self.mCurAttributeValueBegin.c_str(), int_p[assign_a(*(S16*)val_ptr)]).full; } bool LLSimpleXUIParser::readU32Value(Parser& parser, void* val_ptr) { LLSimpleXUIParser& self = static_cast(parser); - return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full; + return parse(self.mCurAttributeValueBegin.c_str(), uint_p[assign_a(*(U32*)val_ptr)]).full; } bool LLSimpleXUIParser::readS32Value(Parser& parser, void* val_ptr) { LLSimpleXUIParser& self = static_cast(parser); - return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full; + return parse(self.mCurAttributeValueBegin.c_str(), int_p[assign_a(*(S32*)val_ptr)]).full; } bool LLSimpleXUIParser::readF32Value(Parser& parser, void* val_ptr) { LLSimpleXUIParser& self = static_cast(parser); - return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full; + return parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(*(F32*)val_ptr)]).full; } bool LLSimpleXUIParser::readF64Value(Parser& parser, void* val_ptr) { LLSimpleXUIParser& self = static_cast(parser); - return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full; + return parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(*(F64*)val_ptr)]).full; } bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr) @@ -1722,7 +1722,7 @@ bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr) LLSimpleXUIParser& self = static_cast(parser); LLColor4 value; - if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) + if (parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) { *(LLColor4*)(val_ptr) = value; return true; @@ -1736,7 +1736,7 @@ bool LLSimpleXUIParser::readUIColorValue(Parser& parser, void* val_ptr) LLColor4 value; LLUIColor* colorp = (LLUIColor*)val_ptr; - if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) + if (parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) { colorp->set(value); return true; @@ -1749,7 +1749,7 @@ bool LLSimpleXUIParser::readUUIDValue(Parser& parser, void* val_ptr) LLSimpleXUIParser& self = static_cast(parser); LLUUID temp_id; // LLUUID::set is destructive, so use temporary value - if (temp_id.set(std::string(self.mCurAttributeValueBegin))) + if (temp_id.set(self.mCurAttributeValueBegin)) { *(LLUUID*)(val_ptr) = temp_id; return true; diff --git a/indra/llui/llxuiparser.h b/indra/llui/llxuiparser.h index 2179ae54d3c..3cc564772ef 100644 --- a/indra/llui/llxuiparser.h +++ b/indra/llui/llxuiparser.h @@ -40,7 +40,7 @@ class LLView; // lookup widget type by name class LLWidgetTypeRegistry -: public LLRegistrySingleton +: public LLRegistrySingleton { LLSINGLETON_EMPTY_CTOR(LLWidgetTypeRegistry); }; @@ -52,7 +52,7 @@ typedef std::function widget_registry_t; class LLChildRegistryRegistry -: public LLRegistrySingleton +: public LLRegistrySingleton { LLSINGLETON_EMPTY_CTOR(LLChildRegistryRegistry); }; @@ -247,7 +247,7 @@ LOG_CLASS(LLSimpleXUIParser); S32 mCurReadDepth; std::string mCurFileName; std::string mTextContents; - const char* mCurAttributeValueBegin; + std::string mCurAttributeValueBegin; std::vector mTokenSizeStack; std::vector mScope; std::vector mEmptyLeafNode; diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp index 8e08239ee60..6bf38cc1f68 100644 --- a/indra/llwebrtc/llwebrtc.cpp +++ b/indra/llwebrtc/llwebrtc.cpp @@ -733,12 +733,17 @@ void LLWebRTCImpl::intSetMute(bool mute, int delay_ms) { mPeerCustomProcessor->setGain(mMute ? 0.0f : mGain); } + + // Sequence counter to prevent race conditions from rapid requests to mute/unmute + static std::atomic mute_sequence(0); + uint32_t current_sequence = ++mute_sequence; + if (mMute) { mWorkerThread->PostDelayedTask( - [this] + [this, current_sequence] { - if (mDeviceModule) + if (mDeviceModule && (current_sequence == mute_sequence.load())) { mDeviceModule->ForceStopRecording(); } @@ -748,9 +753,9 @@ void LLWebRTCImpl::intSetMute(bool mute, int delay_ms) else { mWorkerThread->PostTask( - [this] + [this, current_sequence] { - if (mDeviceModule) + if (mDeviceModule && (current_sequence == mute_sequence.load())) { mDeviceModule->InitRecording(); mDeviceModule->ForceStartRecording(); @@ -1531,6 +1536,57 @@ void LLWebRTCPeerConnectionImpl::unsetDataObserver(LLWebRTCDataObserver* observe } } +class LLStatsCollectorCallback : public webrtc::RTCStatsCollectorCallback +{ +public: + typedef std::function StatsCallback; + + LLStatsCollectorCallback(StatsCallback callback) : callback_(callback) {} + + void OnStatsDelivered(const webrtc::scoped_refptr& report) override + { + if (callback_) + { + // Transform RTCStatsReport stats to simple map + LLWebRTCStatsMap stats_map; + for (const auto& stats : *report) + { + std::map stat_attributes; + + // Convert each attribute to string format + for (const auto& attribute : stats.Attributes()) + { + stat_attributes[attribute.name()] = attribute.ToString(); + } + stats_map[stats.id()] = stat_attributes; + } + callback_(stats_map); + } + } + +private: + StatsCallback callback_; +}; + +void LLWebRTCPeerConnectionImpl::gatherConnectionStats() +{ + if (!mPeerConnection) + { + return; + } + + auto stats_callback = webrtc::make_ref_counted( + [this](const LLWebRTCStatsMap& generic_stats) + { + for (auto& observer : mSignalingObserverList) + { + observer->OnStatsDelivered(generic_stats); + } + }); + + mPeerConnection->GetStats(stats_callback.get()); +} + LLWebRTCImpl * gWebRTCImpl = nullptr; LLWebRTCDeviceInterface * getDeviceInterface() { diff --git a/indra/llwebrtc/llwebrtc.h b/indra/llwebrtc/llwebrtc.h index 7d06b7d2b40..e76e708f0ce 100644 --- a/indra/llwebrtc/llwebrtc.h +++ b/indra/llwebrtc/llwebrtc.h @@ -38,6 +38,7 @@ #ifndef LLWEBRTC_H #define LLWEBRTC_H +#include #include #include @@ -55,6 +56,7 @@ namespace llwebrtc { +typedef std::map> LLWebRTCStatsMap; class LLWebRTCLogCallback { @@ -240,6 +242,8 @@ class LLWebRTCSignalingObserver // Called when the data channel has been established and data // transfer can begin. virtual void OnDataChannelReady(LLWebRTCDataInterface *data_interface) = 0; + + virtual void OnStatsDelivered(const LLWebRTCStatsMap& stats_data) {} }; // LLWebRTCPeerConnectionInterface representsd a connection to a peer, @@ -273,6 +277,8 @@ class LLWebRTCPeerConnectionInterface virtual void unsetSignalingObserver(LLWebRTCSignalingObserver* observer) = 0; virtual void AnswerAvailable(const std::string &sdp) = 0; + + virtual void gatherConnectionStats() = 0; }; // The following define the dynamic linked library diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h index 01cfb17ced2..2ff85c92eeb 100644 --- a/indra/llwebrtc/llwebrtc_impl.h +++ b/indra/llwebrtc/llwebrtc_impl.h @@ -343,6 +343,7 @@ class LLWebRTCAudioDeviceModule : public webrtc::AudioDeviceModule inner_->InitRecording(); inner_->StartRecording(); } + inner_->InitPlayout(); inner_->StartPlayout(); } } @@ -648,6 +649,8 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface, void enableSenderTracks(bool enable); void enableReceiverTracks(bool enable); + void gatherConnectionStats() override; + protected: LLWebRTCImpl * mWebRTCImpl; diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index 562a30e8d17..34643d5f5c1 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -157,9 +157,12 @@ LLControlVariable::LLControlVariable(const std::string& name, eControlType type, { if ((persist != PERSIST_NO) && mComment.empty()) { - // File isn't actually missing, but something is wrong with it - // so the main point is to warn user to reinstall - LLError::LLUserWarningMsg::showMissingFiles(); + std::string error_string = + "Second Life failed to initialize settings. Setting " + mName + " is invalid. " + "Either settings' files were supplied incorrectly or default files were corrupted." + "\n\nPlease reinstall viewer from https://secondlife.com/support/downloads/ and " + "contact https://support.secondlife.com if issue persists after reinstall."; + LLError::LLUserWarningMsg::show(error_string); LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL; } //Push back versus setValue'ing here, since we don't want to call a signal yet @@ -758,6 +761,7 @@ void LLControlGroup::setUntypedValue(std::string_view name, const LLSD& val) // Returns number of controls loaded, so 0 if failure U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, bool require_declaration, eControlType declare_as) { + LL_PROFILE_ZONE_SCOPED; std::string name; LLXmlTree xml_controls; @@ -990,8 +994,9 @@ U32 LLControlGroup::saveToFile(const std::string& filename, bool nondefault_only return num_saved; } -U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values) +U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values, bool error_when_no_comment) { + LL_PROFILE_ZONE_SCOPED; LLSD settings; llifstream infile; infile.open(filename.c_str()); @@ -1105,10 +1110,26 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v } } + std::string comment = control_map["Comment"].asString(); + if (!error_when_no_comment + && !set_default_values + && comment.empty()) + { + // Only error for default settings that should remind the developer to provide comments + // and otherwise indicate a problem with viewer's files. + // But permit this minor transgression in user's files. + // Otherwise user might have a hard time figuring out source of the error or how to fix it. + // Instead make setting to not persist so that unrecognized invalid settings won't be saved + // for the next run. + persist = LLControlVariable::PERSIST_NO; + comment = "Comment not provided, setting won't persist"; + LL_WARNS() << "Control " << name << " is missing a comment value. Setting will be marked as PERSIST_NO" << LL_ENDL; + } + declareControl(name, typeStringToEnum(control_map["Type"].asString()), control_map["Value"], - control_map["Comment"].asString(), + comment, persist, hidefromsettingseditor ); diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index da7268bf457..5aa2b9715ed 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -33,8 +33,10 @@ #include "llrect.h" #include "llrefcount.h" #include "llinstancetracker.h" +#include "llstl.h" #include +#include #include #include @@ -165,7 +167,7 @@ class LLControlGroup : public LLInstanceTracker LOG_CLASS(LLControlGroup); protected: - typedef std::map > ctrl_name_table_t; + using ctrl_name_table_t = std::unordered_map>; ctrl_name_table_t mNameTable; static const std::string mTypeString[TYPE_COUNT]; @@ -278,7 +280,7 @@ class LLControlGroup : public LLInstanceTracker // as the given type. U32 loadFromFileLegacy(const std::string& filename, bool require_declaration = true, eControlType declare_as = TYPE_STRING); U32 saveToFile(const std::string& filename, bool nondefault_only); - U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true); + U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true, bool error_when_no_comment = true); void resetToDefaults(); void incrCount(std::string_view name); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 0949a3b59f2..5818a900f54 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -197,7 +197,6 @@ set(viewer_SOURCE_FILES llfloateravatartextures.cpp llfloaterbanduration.cpp llfloaterbeacons.cpp - llfloaterbigpreview.cpp llfloaterbuildoptions.cpp llfloaterbulkpermission.cpp llfloaterbulkupload.cpp @@ -280,7 +279,6 @@ set(viewer_SOURCE_FILES llfloaterpay.cpp llfloaterperformance.cpp llfloaterperms.cpp - llfloaterpostprocess.cpp llfloaterprofile.cpp llfloaterpreference.cpp llfloaterpreferencesgraphicsadvanced.cpp @@ -305,7 +303,6 @@ set(viewer_SOURCE_FILES llfloatersidepanelcontainer.cpp llfloaterslapptest.cpp llfloatersnapshot.cpp - llfloatersounddevices.cpp llfloaterspellchecksettings.cpp llfloatertelehub.cpp llfloatertestinspectors.cpp @@ -317,7 +314,6 @@ set(viewer_SOURCE_FILES llfloatertranslationsettings.cpp llfloateruipreview.cpp llfloaterurlentry.cpp - llfloatervoiceeffect.cpp llfloatervoicevolume.cpp llfloaterwebcontent.cpp llfloaterwhitelistentry.cpp @@ -420,6 +416,7 @@ set(viewer_SOURCE_FILES llfloaterimnearbychat.cpp llfloaterimnearbychathandler.cpp llfloaterimnearbychatlistener.cpp + llnearbyvoicemoderation.cpp llnetmap.cpp llnotificationalerthandler.cpp llnotificationgrouphandler.cpp @@ -513,7 +510,6 @@ set(viewer_SOURCE_FILES llpanelsnapshotprofile.cpp llpanelteleporthistory.cpp llpaneltiptoast.cpp - llpanelvoiceeffect.cpp llpaneltopinfobar.cpp llpanelpulldown.cpp llpanelvoicedevicesettings.cpp @@ -881,7 +877,6 @@ set(viewer_HEADER_FILES llfloateravatartextures.h llfloaterbanduration.h llfloaterbeacons.h - llfloaterbigpreview.h llfloaterbuildoptions.h llfloaterbulkpermission.h llfloaterbulkupload.h @@ -968,7 +963,6 @@ set(viewer_HEADER_FILES llfloaterpay.h llfloaterperformance.h llfloaterperms.h - llfloaterpostprocess.h llfloaterprofile.h llfloaterpreference.h llfloaterpreferencesgraphicsadvanced.h @@ -993,7 +987,6 @@ set(viewer_HEADER_FILES llfloatersidepanelcontainer.h llfloaterslapptest.h llfloatersnapshot.h - llfloatersounddevices.h llfloaterspellchecksettings.h llfloatertelehub.h llfloatertestinspectors.h @@ -1005,7 +998,6 @@ set(viewer_HEADER_FILES llfloatertranslationsettings.h llfloateruipreview.h llfloaterurlentry.h - llfloatervoiceeffect.h llfloatervoicevolume.h llfloaterwebcontent.h llfloaterwhitelistentry.h @@ -1102,6 +1094,7 @@ set(viewer_HEADER_FILES llnameeditor.h llnamelistctrl.h llnavigationbar.h + llnearbyvoicemoderation.h llnetmap.h llnotificationhandler.h llnotificationlistitem.h @@ -1187,7 +1180,6 @@ set(viewer_HEADER_FILES llpaneltiptoast.h llpanelpulldown.h llpanelvoicedevicesettings.h - llpanelvoiceeffect.h llpaneltopinfobar.h llpanelvolume.h llpanelvolumepulldown.h diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 2aaedf99442..b7397ce158b 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -26.1.0 +26.2.0 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 372a84743fb..e86154ddc1a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -489,6 +489,17 @@ Value 1 + RecentJumpThresholdSecs + + Comment + Seconds after a jump input during which finish-anim is suppressed to avoid interrupting rapid successive jumps. + Persist + 1 + Type + F32 + Value + 1.0 + AvatarAxisDeadZone0 Comment @@ -4591,6 +4602,17 @@ Value 1 + MapShowGridCoords + + Comment + Shows/hides the grid coordinates of each region on the world map. + Persist + 1 + Type + Boolean + Value + 0 + MiniMapAutoCenter Comment @@ -6093,6 +6115,39 @@ Value 0 + OpenDebugStatVoice + + Comment + Expand Voice (WebRTC) stats display + Persist + 1 + Type + Boolean + Value + 1 + + OpenDebugStatVoiceOutgoing + + Comment + Expand Outgoing audio (Voice) stats display + Persist + 1 + Type + Boolean + Value + 1 + + OpenDebugStatVoiceIncoming + + Comment + Expand Incoming audio (Voice) stats display + Persist + 1 + Type + Boolean + Value + 1 + OutBandwidth Comment @@ -10624,6 +10679,17 @@ Value 1 + GroupTitlesTagMode + + Comment + Select Group Titles tag mode: 0 - no group tags, 1 - only my group tag, 2 - all group tags + Persist + 1 + Type + S32 + Value + 2 + ShowAxes Comment @@ -16398,6 +16464,39 @@ Value 0 + InventoryShowRecentTab + + Comment + Show/hide Recent tab in the Inventory floater + Persist + 1 + Type + Boolean + Value + 1 + + InventoryShowWornTab + + Comment + Show/hide Worn tab in the Inventory floater + Persist + 1 + Type + Boolean + Value + 1 + + InventoryShowFavoritesTab + + Comment + Show/hide Favorites tab in the Inventory floater + Persist + 1 + Type + Boolean + Value + 1 + StatsReportMaxDuration Comment @@ -16552,5 +16651,16 @@ Value 2 + PurgeDiskCacheOnStartup + + Comment + Whether or not to LRU purge the disk cache during startup on main thread + Persist + 1 + Type + Boolean + Value + 0 + diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl index dd9e883fdf2..abe61fe8925 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl @@ -146,6 +146,9 @@ vec3 srgb_to_linear(vec3 c); void main() { vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba; + + basecolor.a *= vertex_color.a; + if (basecolor.a < minimum_alpha) { discard; diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index cc9d72fae61..53bd0c741f7 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -51,9 +51,7 @@ in vec3 vary_norm; in vec4 vertex_color; //vertex color should be treated as sRGB #endif -#ifdef HAS_ALPHA_MASK uniform float minimum_alpha; -#endif uniform mat4 proj_mat; uniform mat4 inv_proj; @@ -225,6 +223,13 @@ void main() float final_alpha = diffuse_linear.a; +#ifdef IS_AVATAR_SKIN + if(final_alpha < minimum_alpha) + { + discard; + } +#endif + #ifdef USE_VERTEX_COLOR final_alpha *= vertex_color.a; diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 51fb019e934..bb8adf236a1 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -1027,6 +1027,12 @@ bool Image::prepImpl(Asset& asset, const LLUUID& id) std::string dir = gDirUtilp->getDirName(asset.mFilename); std::string img_file = dir + gDirUtilp->getDirDelimiter() + mUri; + if (!gDirUtilp->fileExists(img_file)) + { + // URI might be escaped, unescape. + img_file = dir + gDirUtilp->getDirDelimiter() + LLURI::unescape(mUri); + } + LLUUID tracking_id = LLLocalBitmapMgr::getInstance()->addUnit(img_file); if (tracking_id.notNull() && mLoadIntoTexturePipe) { diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h index c231443a9e4..53dee98cd1f 100644 --- a/indra/newview/gltf/buffer_util.h +++ b/indra/newview/gltf/buffer_util.h @@ -140,6 +140,42 @@ namespace LL dst = *src; } + template<> + inline void copyScalar(U32* src, LLVector4a& dst) + { + dst.set((F32)*src, 0.f, 0.f, 0.f); + } + + template<> + inline void copyScalar(U16* src, LLVector4a& dst) + { + dst.set((F32)*src, 0.f, 0.f, 0.f); + } + + template<> + inline void copyScalar(U8* src, LLVector4a& dst) + { + dst.set((F32)*src, 0.f, 0.f, 0.f); + } + + template<> + inline void copyScalar(U32* src, LLVector2& dst) + { + dst.set((F32)*src, 0.f); + } + + template<> + inline void copyScalar(U16* src, LLVector2& dst) + { + dst.set((F32)*src, 0.f); + } + + template<> + inline void copyScalar(U8* src, LLVector2& dst) + { + dst.set((F32)*src, 0.f); + } + template<> inline void copyVec2(F32* src, LLVector2& dst) { @@ -220,6 +256,12 @@ namespace LL dst.loadua(src); } + template<> + inline void copyVec4(U32* src, LLVector4a& dst) + { + dst.set((F32)src[0], (F32)src[1], (F32)src[2], (F32)src[3]); + } + template<> inline void copyVec4(U16* src, LLVector4a& dst) { @@ -373,7 +415,7 @@ namespace LL } else { - LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL; + LL_ERRS("GLTF") << "Unsupported accessor type " << (S32)accessor.mType << LL_ENDL; } } diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp index 3a1d8079a93..5a94a2c6c68 100644 --- a/indra/newview/gltf/llgltfloader.cpp +++ b/indra/newview/gltf/llgltfloader.cpp @@ -440,7 +440,25 @@ void LLGLTFLoader::processNodeHierarchy(S32 node_idx, std::map (LLModel::NO_ERRORS == pModel->getStatus()) && validate_model(pModel)) { - mTransform.setIdentity(); + // Build the scene transform. + // Non-skinned meshes: scene transform carries coord rotation + hierarchy, + // preserving the object's rotation/position/scale for upload. + // Skinned meshes: transform is already baked into vertices, so scene is identity. + if (node.mSkin >= 0) + { + mTransform.setIdentity(); + } + else + { + glm::mat4 hierarchy_transform; + computeCombinedNodeTransform(mGLTFAsset, node_idx, hierarchy_transform); + glm::mat4 combined = coord_system_rotation * hierarchy_transform; + if (mApplyXYRotation) + { + combined = coord_system_rotationxy * combined; + } + mTransform = LLMatrix4(glm::value_ptr(combined)); + } transformation = mTransform; // adjust the transformation to compensate for mesh normalization @@ -684,7 +702,12 @@ std::string LLGLTFLoader::processTexture(std::string& full_path_out, S32 texture // Process embedded textures if (image.mBufferView >= 0) { - return extractTextureToTempFile(texture_index, texture_type); + std::string temp_path = extractTextureToTempFile(texture_index, texture_type); + if (!temp_path.empty()) + { + full_path_out = temp_path; + } + return temp_path; } return ""; @@ -734,23 +757,47 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const std::string& bas S32 skinIdx = nodeno.mSkin; - // Compute final combined transform matrix (hierarchy + coordinate rotation) + // Compute the vertex transform for this mesh. + // Non-skinned meshes: vertices are left untransformed; the node's hierarchy transform + // (rotation, translation, scale) is stored in the scene transform instead, matching + // the DAE loader. This ensures the uploaded object's bounding box and transform + // properties are correct. See: https://github.com/secondlife/viewer/issues/5431 + // Skinned meshes: coord rotation + hierarchy are baked into vertex positions because + // inverse bind matrices and skin weights are already computed in that space. + // TODO: consider aligning skinned meshes with the DAE loader (scene transform instead + // of vertex baking), which would require adjusting inverse bind matrices, bind shape + // matrix, and weight keying to match. S32 node_index = static_cast(&nodeno - &mGLTFAsset.mNodes[0]); glm::mat4 hierarchy_transform; computeCombinedNodeTransform(mGLTFAsset, node_index, hierarchy_transform); - // Combine transforms: coordinate rotation applied to hierarchy transform - glm::mat4 final_transform = coord_system_rotation * hierarchy_transform; - if (mApplyXYRotation) + glm::mat4 vertex_transform; + if (skinIdx >= 0) { - final_transform = coord_system_rotationxy * final_transform; + // Skinned mesh: bake coord rotation + hierarchy into vertices. + // Inverse bind matrices and skin weights depend on this transform being applied. + vertex_transform = coord_system_rotation * hierarchy_transform; + if (mApplyXYRotation) + { + vertex_transform = coord_system_rotationxy * vertex_transform; + } + } + else + { + // Non-skinned mesh: don't apply any transform to vertices. + // The hierarchy transform will be stored in the scene transform matrix. + vertex_transform = glm::mat4(1.0f); // identity } // Check if we have a negative scale (flipped coordinate system) - bool hasNegativeScale = glm::determinant(final_transform) < 0.0f; + // coord_system_rotation and coord_system_rotationxy are pure rotations (det=1), + // so negative scale depends only on the hierarchy transform. + bool hasNegativeScale = glm::determinant(hierarchy_transform) < 0.0f; + + bool hasVertexTransform = (vertex_transform != glm::mat4(1.0f)); // Pre-compute normal transform matrix (transpose of inverse of upper-left 3x3) - const glm::mat3 normal_transform = glm::transpose(glm::inverse(glm::mat3(final_transform))); + const glm::mat3 normal_transform = glm::transpose(glm::inverse(glm::mat3(vertex_transform))); // Mark unsuported joints with '-1' so that they won't get added into weights // GLTF maps all joints onto all meshes. Gather use count per mesh to cut unused ones. @@ -803,30 +850,49 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const std::string& bas return false; // Skip this primitive } - // Apply the global scale and center offset to all vertices + // Apply vertex transform (if any) to all vertices. + // Skinned meshes: this bakes coord rotation + hierarchy into vertices. + // Non-skinned meshes: vertex_transform is identity (no baking). for (U32 i = 0; i < prim.getVertexCount(); i++) { - // Use pre-computed final_transform - glm::vec4 pos(prim.mPositions[i][0], prim.mPositions[i][1], prim.mPositions[i][2], 1.0f); - glm::vec4 transformed_pos = final_transform * pos; - GLTFVertex vert; - vert.position = glm::vec3(transformed_pos); - if (!prim.mNormals.empty()) + if (hasVertexTransform) { - // Use pre-computed normal_transform - glm::vec3 normal_vec(prim.mNormals[i][0], prim.mNormals[i][1], prim.mNormals[i][2]); - vert.normal = glm::normalize(normal_transform * normal_vec); + glm::vec4 pos(prim.mPositions[i][0], prim.mPositions[i][1], prim.mPositions[i][2], 1.0f); + glm::vec4 transformed_pos = vertex_transform * pos; + vert.position = glm::vec3(transformed_pos); + + if (!prim.mNormals.empty()) + { + glm::vec3 normal_vec(prim.mNormals[i][0], prim.mNormals[i][1], prim.mNormals[i][2]); + vert.normal = glm::normalize(normal_transform * normal_vec); + } + else + { + vert.normal = glm::normalize(normal_transform * glm::vec3(0.0f, 0.0f, 1.0f)); + LL_DEBUGS("GLTF_IMPORT") << "No normals found for primitive, using default normal." << LL_ENDL; + } } else { - // Use default normal (pointing up in model space) - vert.normal = glm::normalize(normal_transform * glm::vec3(0.0f, 0.0f, 1.0f)); - LL_DEBUGS("GLTF_IMPORT") << "No normals found for primitive, using default normal." << LL_ENDL; + // No transform: store raw GLTF positions and normals. + // The scene transform will carry coord rotation + hierarchy. + vert.position = glm::vec3(prim.mPositions[i][0], prim.mPositions[i][1], prim.mPositions[i][2]); + + if (!prim.mNormals.empty()) + { + vert.normal = glm::vec3(prim.mNormals[i][0], prim.mNormals[i][1], prim.mNormals[i][2]); + } + else + { + vert.normal = glm::vec3(0.0f, 0.0f, 1.0f); + LL_DEBUGS("GLTF_IMPORT") << "No normals found for primitive, using default normal." << LL_ENDL; + } } - vert.uv0 = glm::vec2(prim.mTexCoords0[i][0], -prim.mTexCoords0[i][1]); + // Flip texture V coordinate + vert.uv0 = glm::vec2(prim.mTexCoords0[i][0], 1.f - prim.mTexCoords0[i][1]); if (skinIdx >= 0) { diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 0e366980185..ae40e8830fb 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -767,8 +767,21 @@ Function un.UserSettingsFiles StrCmp $DO_UNINSTALL_V2 "true" Keep # Don't remove user's settings files on auto upgrade -# Ask if user wants to keep data files or not -MessageBox MB_YESNO|MB_ICONQUESTION $(RemoveDataFilesMB) IDYES Remove IDNO Keep +ClearErrors +Push $0 +${GetParameters} $COMMANDLINE +${GetOptionsS} $COMMANDLINE "/clrusrfiles" $0 +# GetOptionsS returns an error if option does not exist, jump past Goto. +IfErrors +3 0 + Pop $0 + Goto Remove + +Pop $0 +ClearErrors + +ifSilent Keep 0 + # Ask if user wants to keep data files or not + MessageBox MB_YESNO|MB_ICONQUESTION $(RemoveDataFilesMB) IDYES Remove IDNO Keep Remove: Push $0 @@ -864,11 +877,25 @@ RMDir "$INSTDIR" IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER FOLDERFOUND: +ifSilent NOFOLDER 0 MessageBox MB_OK $(DeleteProgramFilesMB) /SD IDOK IDOK NOFOLDER NOFOLDER: -MessageBox MB_YESNO $(DeleteRegistryKeysMB) IDYES DeleteKeys IDNO NoDelete +ClearErrors +Push $0 +${GetParameters} $COMMANDLINE +${GetOptionsS} $COMMANDLINE "/clearreg" $0 +# GetOptionsS returns an error if option does not exist, jump past Goto. +IfErrors +3 0 + Pop $0 + Goto DeleteKeys + +Pop $0 +ClearErrors + +ifSilent NoDelete 0 + MessageBox MB_YESNO $(DeleteRegistryKeysMB) IDYES DeleteKeys IDNO NoDelete DeleteKeys: DeleteRegKey SHELL_CONTEXT "SOFTWARE\Classes\x-grid-location-info" diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 0d7ad0a1246..3ab87cac137 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -426,6 +426,7 @@ LLAgent::LLAgent() : mIsDoNotDisturb(false), mControlFlags(0x00000000), + mLastJumpInputTime(0.0), mAutoPilot(false), mAutoPilotFlyOnStop(false), @@ -780,6 +781,10 @@ void LLAgent::moveUp(S32 direction) if (direction > 0) { + if (!getFlying()) + { + mLastJumpInputTime = LLTimer::getTotalSeconds(); + } setControlFlags(AGENT_CONTROL_UP_POS | AGENT_CONTROL_FAST_UP); } else if (direction < 0) @@ -2663,7 +2668,21 @@ void LLAgent::onAnimStop(const LLUUID& id) } else if (id == ANIM_AGENT_PRE_JUMP || id == ANIM_AGENT_LAND || id == ANIM_AGENT_MEDIUM_LAND) { - setControlFlags(AGENT_CONTROL_FINISH_ANIM); + // FIRE-34049/FIRE-34273/https://github.com/secondlife/viewer/issues/4218 + // Avoid forcing AGENT_CONTROL_FINISH_ANIM, which can short-circuit the next pre-jump + // during rapid successive jumps. + // TODO: a more robust fix would require knowing which specific animation finished, + // information that is not currently provided by the simulator. + const bool up_pos = (mControlFlags & AGENT_CONTROL_UP_POS) != 0; + const F64 now = LLTimer::getTotalSeconds(); + const F64 elapsed = now - mLastJumpInputTime; + static LLCachedControl recent_jump_threshold_secs(gSavedSettings, "RecentJumpThresholdSecs"); + const bool recent_jump = (mLastJumpInputTime > 0.0) && (elapsed < recent_jump_threshold_secs); + + if (!up_pos && !recent_jump) + { + setControlFlags(AGENT_CONTROL_FINISH_ANIM); + } } } @@ -4850,6 +4869,8 @@ const std::string& LLAgent::getTeleportStateName() const void LLAgent::parseTeleportMessages(const std::string& xml_filename) { + LL_PROFILE_ZONE_SCOPED; + LLXMLNodePtr root; bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 3352890d999..e6d9623957f 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -487,6 +487,7 @@ class LLAgent : public LLOldEvents::LLObservable S32 mControlsTakenCount[TOTAL_CONTROLS]; S32 mControlsTakenPassedOnCount[TOTAL_CONTROLS]; U32 mControlFlags; // Replacement for the mFooKey's + F64 mLastJumpInputTime; // Time of last jump input (key-down) in seconds from LLTimer::getTotalSeconds() //-------------------------------------------------------------------- // Animations diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index b2c66b1bace..d884b32ac04 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -975,6 +975,10 @@ void LLAgentCamera::cameraZoomIn(const F32 fraction) new_distance = llclamp(new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM); } } + else + { + new_distance = llmin(new_distance, getCameraMaxZoomDistance()); + } mCameraFocusOffsetTarget = new_distance * camera_offset_unit; } @@ -1035,6 +1039,10 @@ void LLAgentCamera::cameraOrbitIn(const F32 meters) new_distance = llclamp(new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM); } } + else + { + new_distance = llmin(new_distance, getCameraMaxZoomDistance()); + } // Compute new camera offset mCameraFocusOffsetTarget = new_distance * camera_offset_unit; diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 9c76f56ef31..f67f2688a16 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -1019,6 +1019,9 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht } //------------------------------------------------------------------------- +U32 AISUpdate::sBatchFrameCount = 0; +LLTimer AISUpdate::sBatchTimer; + AISUpdate::AISUpdate(const LLSD& update, AISAPI::COMMAND_TYPE type, const LLSD& request_body) : mType(type) { @@ -1036,8 +1039,16 @@ AISUpdate::AISUpdate(const LLSD& update, AISAPI::COMMAND_TYPE type, const LLSD& mFetchDepth = request_body["depth"].asInteger(); } - mTimer.setTimerExpirySec(AIS_EXPIRY_SECONDS); - mTimer.start(); + mTaskTimer.setTimerExpirySec(AIS_TASK_EXPIRY_SECONDS); + mTaskTimer.start(); + + U32 current_frame = LLFrameTimer::getFrameCount(); + if (sBatchFrameCount != current_frame) + { + sBatchTimer.setTimerExpirySec(AIS_BATCH_EXPIRY_SECONDS); + sBatchTimer.start(); + sBatchFrameCount = current_frame; + } parseUpdate(update); } @@ -1058,7 +1069,7 @@ void AISUpdate::clearParseResults() void AISUpdate::checkTimeout() { - if (mTimer.hasExpired()) + if (mTaskTimer.hasExpired() || sBatchTimer.hasExpired()) { // If we are taking too long, don't starve other tasks, // yield to mainloop. @@ -1067,7 +1078,16 @@ void AISUpdate::checkTimeout() // a chance, so wait for a frame tick instead. llcoro::suspendUntilNextFrame(); LLCoros::checkStop(); - mTimer.setTimerExpirySec(AIS_EXPIRY_SECONDS); + mTaskTimer.setTimerExpirySec(AIS_TASK_EXPIRY_SECONDS); + + U32 current_frame = LLFrameTimer::getFrameCount(); + if (sBatchFrameCount != current_frame) + { + // To give other tasks a chance batch timer + // has a longer delay. + sBatchTimer.setTimerExpirySec(AIS_BATCH_EXPIRY_SECONDS); + sBatchFrameCount = current_frame; + } } } diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index cfc286da2e8..1dab0dd1f91 100644 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -130,9 +130,13 @@ class AISUpdate void clearParseResults(); void checkTimeout(); - // Fetch can return large packets of data, throttle it to not cause lags - // Todo: make throttle work over all fetch requests isntead of per-request - const F32 AIS_EXPIRY_SECONDS = 0.008f; + // Fetches can return large packets of data, + // throttle them individually to not get stuck + // on a single large task. And throttle sum total + // to not cause lags when multiple large fetches + // returned results. + const F32 AIS_TASK_EXPIRY_SECONDS = 0.008f; + const F32 AIS_BATCH_EXPIRY_SECONDS = 0.010f; typedef std::map uuid_int_map_t; uuid_int_map_t mCatDescendentDeltas; @@ -154,7 +158,9 @@ class AISUpdate uuid_list_t mCategoryIds; bool mFetch; S32 mFetchDepth; - LLTimer mTimer; + LLTimer mTaskTimer; + static LLTimer sBatchTimer; + static U32 sBatchFrameCount; AISAPI::COMMAND_TYPE mType; }; diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index f3265afebd0..ece18fb5cc4 100644 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -144,6 +144,8 @@ LLAppCoreHttp::~LLAppCoreHttp() void LLAppCoreHttp::init() { + LL_PROFILE_ZONE_SCOPED; + LLCoreHttpUtil::setPropertyMethods( std::bind(&LLControlGroup::getBOOL, std::ref(gSavedSettings), std::placeholders::_1), std::bind(&LLControlGroup::declareBOOL, std::ref(gSavedSettings), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, LLControlVariable::PERSIST_NONDFT)); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 9a421972e58..288da8ead85 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -343,9 +343,6 @@ F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME; S32 gPendingMetricsUploads = 0; - -bool gDisconnected = false; - // Used to restore texture state after a mode switch LLFrameTimer gRestoreGLTimer; bool gRestoreGL = false; @@ -380,6 +377,7 @@ const std::string MARKER_FILE_NAME("SecondLife.exec_marker"); const std::string START_MARKER_FILE_NAME("SecondLife.start_marker"); const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker"); const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker"); +const std::string WATCHDOG_MARKER_FILE_NAME("SecondLife.watchdog_marker"); static std::string gLaunchFileOnQuit; // Used on Win32 for other apps to identify our window (eg, win_setup) @@ -735,6 +733,8 @@ class LLUITranslationBridge : public LLTranslationBridge bool LLAppViewer::init() { + LL_PROFILE_ZONE_SCOPED; + setupErrorHandling(mSecondInstance); // @@ -936,6 +936,7 @@ bool LLAppViewer::init() // Early out from user choice. LL_WARNS("InitInfo") << "initHardwareTest() failed." << LL_ENDL; // quit immediately + LL_PROFILER_FRAME_END; return false; } LL_INFOS("InitInfo") << "Hardware test initialization done." << LL_ENDL ; @@ -954,12 +955,14 @@ bool LLAppViewer::init() OSMessageBox(msg.c_str(), LLStringUtil::null, OSMB_OK); LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL; // quit immediately + LL_PROFILER_FRAME_END; return false; } LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ; // Initialize event recorder LLViewerEventRecorder::createInstance(); + LLWatchdog::createInstance(); // // Initialize the window @@ -989,6 +992,7 @@ bool LLAppViewer::init() // Already handled with a MBVideoDrvErr LL_WARNS("InitInfo") << "gGLManager.mHasRequirements is false." << LL_ENDL; // quit immediately + LL_PROFILER_FRAME_END; return false; } @@ -1002,6 +1006,7 @@ bool LLAppViewer::init() OSMessageBox(msg.c_str(), LLStringUtil::null, OSMB_OK); LL_WARNS("InitInfo") << "SSE2 is not supported" << LL_ENDL; // quit immediately + LL_PROFILER_FRAME_END; return false; } #endif @@ -1272,7 +1277,7 @@ bool LLAppViewer::init() gDirUtilp->deleteDirAndContents(gDirUtilp->getDumpLogsDirPath()); } #endif - + LL_PROFILER_FRAME_END; return true; } @@ -2203,6 +2208,8 @@ void LLAppViewer::initGeneralThread() bool LLAppViewer::initThreads() { + LL_PROFILE_ZONE_SCOPED; + static const bool enable_threads = true; LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange")); @@ -2482,7 +2489,10 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, file.file_name()); } - if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent)) + // Be softer for files in the user's folders, user can't just reinstall those + bool error_when_no_comment = !set_defaults && location_key != "User"; + + if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent, error_when_no_comment)) { // success! LL_INFOS("Settings") << "Loaded settings file " << full_settings_path << LL_ENDL; } @@ -3047,6 +3057,8 @@ bool LLAppViewer::initConfiguration() // keeps growing, necessitating a method all its own. void LLAppViewer::initStrings() { + LL_PROFILE_ZONE_SCOPED; + std::string strings_file = "strings.xml"; std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file); if (strings_path_full.empty() || !LLFile::isfile(strings_path_full)) @@ -3136,6 +3148,7 @@ void LLAppViewer::sendOutOfDiskSpaceNotification() bool LLAppViewer::initWindow() { + LL_PROFILE_ZONE_SCOPED; LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL; // store setting in a global for easy access and modification @@ -3189,20 +3202,60 @@ bool LLAppViewer::initWindow() << " (setting = " << watchdog_enabled_setting << ")" << LL_ENDL; - if (use_watchdog) + // Watchdog reports to statistics via marker files, that is + // pointless without ability to write (!mSecondInstance) those files. + // If use_watchdog is set, watchdog also reports to bugspat. + if (use_watchdog || !mSecondInstance) { - LLWatchdog::getInstance()->init([]() - { - LLAppViewer* app = LLAppViewer::instance(); - if (app->logoutRequestSent()) + LLWatchdog::getInstance()->init( + [](bool final_marker) { - app->createErrorMarker(LAST_EXEC_LOGOUT_FROZE); - } - else + LLAppViewer* app = LLAppViewer::instance(); + // Without watchdog everything will be counted as + // either 'unknown' (no crash marker) or based of present crash marker + if (final_marker) + { + // watchdog is going to crash viewer, so crate a 'crash' marker + if (app->logoutRequestSent()) + { + app->createErrorMarker(LAST_EXEC_LOGOUT_FROZE); + } + else + { + app->createErrorMarker(LAST_EXEC_FROZE); + } + } + else + { + // not going to crash, just create a 'watchdog' marker + app->createWatchdogMarker(); + } + }, + []() { - app->createErrorMarker(LAST_EXEC_FROZE); - } - }); + LLAppViewer* app = LLAppViewer::instance(); + // in case process recovered from freeze, remove watchdog marker. + app->removeWatchdogMarker(); + }, + [](std::string &desc) + { +#if LL_WINDOWS && LL_BUGSPLAT + LLAppViewer* app = LLAppViewer::instance(); + app->writeDebugInfo(); + return app->reportCustomToBugsplat(desc); +#else + return false; +#endif + }, + []() + { + LLAppViewer* app = LLAppViewer::instance(); + app->sendLogoutRequest(); + // Might be better to ask user if user wants to terminate the app or wait. + OSMessageBox(LLTrans::getString("MBFreezeDetected"), LLTrans::getString("MBFatalError"), OSMB_OK); + }, + use_watchdog); + } LLNotificationsUI::LLNotificationManager::getInstance(); @@ -3985,13 +4038,8 @@ void LLAppViewer::processMarkerFiles() { // the file existed, is ours, and matched our version, so we can report on what it says LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed or froze" << LL_ENDL; -#if LL_WINDOWS && LL_BUGSPLAT - // bugsplat will set correct state in bugsplatSendLog - // Might be more accurate to rename this one into 'unknown' + // App terminated unexpectedly or froze, we don't know the cause yet. gLastExecEvent = LAST_EXEC_UNKNOWN; -#else - gLastExecEvent = LAST_EXEC_OTHER_CRASH; -#endif // LL_WINDOWS } else @@ -4044,23 +4092,29 @@ void LLAppViewer::processMarkerFiles() } LLAPRFile::remove(logout_marker_file); } - // and last refine based on whether or not a marker created during a non-llerr crash is found + // Refine based on whether or not a marker created during + // a crash is found or if wathdog caught a freeze. + // Bugsplat will set correct state in bugsplatSendLog. std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); + std::string watchdog_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, WATCHDOG_MARKER_FILE_NAME); if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) { S32 marker_code = getMarkerErrorCode(error_marker_file); if (marker_code >= 0) { - if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) - { - gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; - LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; - } - else if (marker_code > 0 && marker_code < (S32)LAST_EXEC_COUNT) + if (marker_code > 0 && marker_code < (S32)LAST_EXEC_COUNT) { + // If we have a code, it takes precendence gLastExecEvent = (eLastExecEvent)marker_code; LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; } + // if we have the marker, even without a code, it's a crash. + else if (gLastExecEvent == LAST_EXEC_LOGOUT_UNKNOWN + || gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) + { + gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; + LL_INFOS("MarkerFile") << "Error marker '" << error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; + } else { gLastExecEvent = LAST_EXEC_OTHER_CRASH; @@ -4072,6 +4126,33 @@ void LLAppViewer::processMarkerFiles() LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL; } LLAPRFile::remove(error_marker_file); + if (LLAPRFile::isExist(watchdog_marker_file, NULL, LL_APR_RB)) + { + // If viewer crashed after a freeze was detected, + // crash still takes precendence. Just clear watchdog. + removeWatchdogMarker(); + } + } + else + { + // so only check watchdog marker if there is no error marker. + if (LLAPRFile::isExist(watchdog_marker_file, NULL, LL_APR_RB)) + { + if (LAST_EXEC_UNKNOWN == gLastExecEvent + || LAST_EXEC_LOGOUT_UNKNOWN == gLastExecEvent) + { + // watchdog marker gets created if we detect a freeze, + // so if viwer did not stop gracefully, and we know it wasn't a crash, + // we have no other info, check watchdog. + if (markerIsSameVersion(watchdog_marker_file)) + { + gLastExecEvent = LAST_EXEC_UNKNOWN == gLastExecEvent ? LAST_EXEC_FROZE : LAST_EXEC_LOGOUT_FROZE; + LL_INFOS("MarkerFile") << "Watchdog marker '" << watchdog_marker_file << "' found, setting LastExecEvent to FROZE" + << LL_ENDL; + } + } + removeWatchdogMarker(); + } } #if LL_DARWIN @@ -4116,6 +4197,7 @@ void LLAppViewer::removeMarkerFiles() { LL_WARNS("MarkerFile") << "logout marker '"<setReadOnly(read_only) ; @@ -4470,19 +4553,22 @@ bool LLAppViewer::initCache() if (mPurgeCache) { - LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); - purgeCache(); + LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); + purgeCache(); // clear the new C++ file system based cache LLDiskCache::getInstance()->clearCache(); - } - else + } + else if (gSavedSettings.getBOOL("PurgeDiskCacheOnStartup")) { // purge excessive files from the new file system based cache LLDiskCache::getInstance()->purge(); } + + // Start disk cache purge thread to + // purge excessive files from the file system based cache + LLAppViewer::getPurgeDiskCacheThread()->start(); } - LLAppViewer::getPurgeDiskCacheThread()->start(); LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache")); @@ -4525,6 +4611,7 @@ void LLAppViewer::loadKeyBindings() // As per GHI #4498, remove old, stale CEF cache folders from previous sessions void LLAppViewer::purgeCefStaleCaches() { + LL_PROFILE_ZONE_SCOPED; // TODO: we really shouldn't use a hard coded name for the cache folder here... const std::string browser_parent_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "cef_cache"); if (LLFile::isdir(browser_parent_cache)) @@ -4552,7 +4639,19 @@ void LLAppViewer::purgeCacheImmediate() { LL_INFOS("AppCache") << "Purging Object Cache and Texture Cache immediately..." << LL_ENDL; LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE, false); - LLVOCache::getInstance()->removeCache(LL_PATH_CACHE, true); + if (LLVOCache::instanceExists()) + { + LLVOCache::getInstance()->removeCache(LL_PATH_CACHE, true); + } + else if (!mSecondInstance) + { + // LLVOCache requires parameters to be initialized, if it's not there, try manually + std::string mask = "*"; + std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "objectcache"); + LL_INFOS() << "Removing cache at " << cache_dir << LL_ENDL; + gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files + LLFile::rmdir(cache_dir); + } } std::string LLAppViewer::getSecondLifeTitle() const @@ -4720,6 +4819,8 @@ std::string get_name_cache_filename(const std::string &base_file, const std::str void LLAppViewer::loadNameCache() { + LL_PROFILE_ZONE_SCOPED; + // display names cache std::string filename = get_name_cache_filename("avatar_name_cache", "xml"); LL_INFOS("AvNameCache") << filename << LL_ENDL; @@ -5484,6 +5585,30 @@ bool LLAppViewer::errorMarkerExists() const return LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB); } +void LLAppViewer::createWatchdogMarker() const +{ + if (!mSecondInstance) + { + std::string error_marker = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, WATCHDOG_MARKER_FILE_NAME); + + LLAPRFile file; + file.open(error_marker, LL_APR_WB); + if (file.getFileHandle()) + { + recordMarkerVersion(file); + file.close(); + } + } +} +void LLAppViewer::removeWatchdogMarker() const +{ + if (!mSecondInstance) + { + std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, WATCHDOG_MARKER_FILE_NAME); + LLFile::remove(error_marker_file); + } +} + void LLAppViewer::outOfMemorySoftQuit() { if (!mQuitRequested) diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 6b0d3e0b27c..71033b6d3fb 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -257,6 +257,9 @@ class LLAppViewer : public LLApp void createErrorMarker(eLastExecEvent error_code) const; bool errorMarkerExists() const; + void createWatchdogMarker() const; + void removeWatchdogMarker() const; + // Attempt a 'soft' quit with disconnect and saving of settings/cache. // Intended to be thread safe. // Good chance of viewer crashing either way, but better than alternatives. @@ -417,8 +420,6 @@ extern S32 gPendingMetricsUploads; extern F32 gSimLastTime; extern F32 gSimFrames; -extern bool gDisconnected; - extern LLFrameTimer gRestoreGLTimer; extern bool gRestoreGL; extern bool gUseWireframe; diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 0620b625d9b..45c8c369cac 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -114,6 +114,7 @@ namespace // MiniDmpSender pointer. As things stand, though, we must define an // actual function and store the pointer statically. static MiniDmpSender *sBugSplatSender = nullptr; + static std::string sBugsplatDesriptionField; bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2) { @@ -150,8 +151,21 @@ namespace WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "settings_per_account.xml"))); } - // LL_ERRS message, when there is one - sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage())); + if (!sBugsplatDesriptionField.empty()) + { + // Can be set by watchdog or other code that detects a problem + // and wants to add some context to the crash report. + // Will be visible in the BugSplat web UI. + sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage())); + // This type of crash is not nessesarily a crash, or final. + // Prepare for the next one. + sBugsplatDesriptionField.clear(); + } + else + { + // LL_ERRS message, when there is one + sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage())); + } sBugSplatSender->setAttribute(WCSTR(L"OS"), WCSTR(LLOSInfo::instance().getOSStringSimple())); // In case we ever stop using email for this sBugSplatSender->setAttribute(WCSTR(L"AppState"), WCSTR(LLStartUp::getStartupStateString())); @@ -833,6 +847,38 @@ bool LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo) return false; } +#if defined(LL_BUGSPLAT) +static int reportCustomToBugsplatFilter(EXCEPTION_POINTERS* pExcepInfo) +{ + if (sBugSplatSender) + { + sBugSplatSender->createReport(pExcepInfo); + } + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + +bool LLAppViewerWin32::reportCustomToBugsplat(const std::string &description) +{ +#if defined(LL_BUGSPLAT) + if (sBugSplatSender) + { + sBugsplatDesriptionField = description; + + __try + { + // Generate a custom exception code + RaiseException(0xE0000001, 0, 0, NULL); + } + __except (reportCustomToBugsplatFilter(GetExceptionInformation())) + { + } + return true; + } +#endif // LL_BUGSPLAT + return false; +} + bool LLAppViewerWin32::initWindow() { // This is a workaround/hotfix for a change in Windows 11 24H2 (and possibly later) diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index 3fad53ec72b..5abcca1ce9e 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -44,6 +44,7 @@ class LLAppViewerWin32 : public LLAppViewer bool cleanup() override; bool reportCrashToBugsplat(void* pExcepInfo) override; + bool reportCustomToBugsplat(const std::string& desription) override; protected: bool initWindow() override; // Override to initialize the viewer's window. diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 6f6b89ea81e..fb1426a2353 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -29,8 +29,6 @@ #include "llavataractions.h" -#include "boost/lambda/lambda.hpp" // for lambda::constant - #include "llavatarnamecache.h" // IDEVO #include "llsd.h" #include "llnotifications.h" diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp index 80c7f8beca1..de3ce901c13 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -47,7 +47,7 @@ S32 LLAvatarListItem::sLeftPadding = 0; S32 LLAvatarListItem::sNameRightPadding = 0; S32 LLAvatarListItem::sChildrenWidths[LLAvatarListItem::ALIC_COUNT]; -static LLWidgetNameRegistry::StaticRegistrar sRegisterAvatarListItemParams(&typeid(LLAvatarListItem::Params), "avatar_list_item"); +static LLWidgetNameRegistry::StaticRegistrar sRegisterAvatarListItemParams(typeid(LLAvatarListItem::Params), "avatar_list_item"); LLAvatarListItem::Params::Params() : default_style("default_style"), diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index 76e308a9660..2c9d74ed97d 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -680,6 +680,8 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg) LLNotifications::instance().add("RevokedModifyRights",args, payload); } } + // update modify permissions flags for affected objects + LLViewerObject::markObjectsForUpdate(agent_id); (mBuddyInfo[agent_id])->setRightsFrom(new_rights); } } diff --git a/indra/newview/llcapabilityprovider.h b/indra/newview/llcapabilityprovider.h index 484bd2ef044..acc752588dc 100644 --- a/indra/newview/llcapabilityprovider.h +++ b/indra/newview/llcapabilityprovider.h @@ -37,12 +37,12 @@ class LLCapabilityProvider { public: - virtual ~LLCapabilityProvider() {} + virtual ~LLCapabilityProvider() = default; /** * Get a capability URL, given a capability name. Returns empty string if * no such capability is defined on this provider. */ - virtual std::string getCapability(const std::string& name) const = 0; + virtual std::string getCapability(std::string_view name) const = 0; /** * Get host to which to send that capability request. */ diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp index 47803edc738..6bd15d4b617 100644 --- a/indra/newview/llcofwearables.cpp +++ b/indra/newview/llcofwearables.cpp @@ -647,7 +647,7 @@ void LLCOFWearables::addClothingTypesDummies(const LLAppearanceMgr::wearables_by for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++) { - if (clothing_by_type[type].empty()) + if (!clothing_by_type[type].empty()) continue; LLWearableType::EType w_type = static_cast(type); diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 99d770b6e27..2297fddf0ce 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -59,11 +59,18 @@ class LLNearbyVoiceClientStatusObserver : public LLVoiceClientStatusObserver virtual void onChange(EStatusType status, const LLSD& channelInfo, bool proximal) { + bool voice_enabled = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); conversation->showVoiceIndicator(conversation && status != STATUS_JOINING && status != STATUS_LEFT_CHANNEL - && LLVoiceClient::getInstance()->voiceEnabled() - && LLVoiceClient::getInstance()->isVoiceWorking()); + && voice_enabled); + + static bool s_voice_enabled(false); + if (s_voice_enabled != voice_enabled) + { + s_voice_enabled = voice_enabled; + conversation->updateConversationIndicators(); + } } private: @@ -509,11 +516,25 @@ void LLConversationViewSession::refresh() // Update all speaking indicators LLSpeakingIndicatorManager::updateSpeakingIndicators(); + updateConversationIndicators(); + + requestArrange(); + if (vmi) + { + // Do the regular upstream refresh + LLFolderViewFolder::refresh(); + } +} + +void LLConversationViewSession::updateConversationIndicators() +{ + bool is_active_channel = isInActiveVoiceChannel(); + // we should show indicator for specified voice session only if this is current channel. EXT-5562. if (mSpeakingIndicator) { - mSpeakingIndicator->setIsActiveChannel(mIsInActiveVoiceChannel); - mSpeakingIndicator->setShowParticipantsSpeaking(mIsInActiveVoiceChannel); + mSpeakingIndicator->setIsActiveChannel(is_active_channel); + mSpeakingIndicator->setShowParticipantsSpeaking(is_active_channel); } LLConversationViewParticipant* participant = NULL; @@ -523,16 +544,9 @@ void LLConversationViewSession::refresh() participant = dynamic_cast(*iter); if (participant) { - participant->allowSpeakingIndicator(mIsInActiveVoiceChannel); + participant->allowSpeakingIndicator(is_active_channel); } } - - requestArrange(); - if (vmi) - { - // Do the regular upstream refresh - LLFolderViewFolder::refresh(); - } } void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& session_id) @@ -543,7 +557,7 @@ void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& sessi { bool old_value = mIsInActiveVoiceChannel; mIsInActiveVoiceChannel = vmi->getUUID() == session_id; - mCallIconLayoutPanel->setVisible(mIsInActiveVoiceChannel && !LLVoiceChannel::isSuspended()); + mCallIconLayoutPanel->setVisible(isInActiveVoiceChannel() && !LLVoiceChannel::isSuspended()); if (old_value != mIsInActiveVoiceChannel) { refresh(); @@ -567,6 +581,13 @@ bool LLConversationViewSession::highlightFriendTitle(LLConversationItem* vmi) return false; } +bool LLConversationViewSession::isInActiveVoiceChannel() +{ + return mIsInActiveVoiceChannel && + LLVoiceClient::getInstance()->voiceEnabled() && + LLVoiceClient::getInstance()->isVoiceWorking(); +} + // // Implementation of conversations list participant (avatar) widgets // diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h index a6d240ed841..58440411278 100644 --- a/indra/newview/llconversationview.h +++ b/indra/newview/llconversationview.h @@ -94,7 +94,8 @@ class LLConversationViewSession : public LLFolderViewFolder void setHighlightState(bool hihglight_state); LLFloater* getSessionFloater(); - bool isInActiveVoiceChannel() { return mIsInActiveVoiceChannel; } + bool isInActiveVoiceChannel(); + void updateConversationIndicators(); bool highlightFriendTitle(LLConversationItem* vmi); diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 322ee90541c..da9378ad129 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -723,9 +723,13 @@ F32 LLDrawable::updateXform(bool undamped) mXform.setRotation(target_rot); mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!) mXform.updateMatrix(); - if (isRoot() && mVObjp->isAnimatedObject() && mVObjp->getControlAvatar()) + if (isRoot() && mVObjp->isAnimatedObject()) { - mVObjp->getControlAvatar()->matchVolumeTransform(); + LLControlAvatar* cav = mVObjp->getControlAvatar(); + if (cav) + { + cav->matchVolumeTransform(); + } } if (mSpatialBridge) diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index bc45734e667..9d1b11880b5 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -267,7 +267,7 @@ void LLDrawPoolAlpha::forwardRender(bool rigged) gGL.setColorMask(true, false); - if (!rigged) + if (!rigged && getType() == LLDrawPoolAlpha::POOL_ALPHA_POST_WATER) { //render "highlight alpha" on final non-rigged pass // NOTE -- hacky call here protected by !rigged instead of alongside "forwardRender" // so renderDebugAlpha is executed while gls_pipeline_alpha and depth GL state diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index f1b46f05331..9eddec55c58 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -73,9 +73,9 @@ namespace Details // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error. // This means we attempt to recover relatively quickly but back off giving more time to recover // until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts. - constexpr F32 EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout. - constexpr F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout. - constexpr S32 MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules. + constexpr F32 EVENT_POLL_ERROR_RETRY_SECONDS = 1.f; + constexpr F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 3.f; + constexpr S32 MAX_EVENT_POLL_ERRORS = 15; // ~5 minutes, by the above rules. constexpr F64 MIN_SECONDS_PASSED = 10.0; // Minimum time we expect the server to hold the request. int LLEventPollImpl::sNextCounter = 1; @@ -238,23 +238,26 @@ namespace Details } else if (!status.isHttpStatus()) { - /// Some LLCore or LIBCurl error was returned. This is unlikely to be recoverable - LL_WARNS("LLEventPollImpl") << "<" << counter << "> Critical error from poll request returned from libraries. Canceling coroutine." << LL_ENDL; - break; + // Some LLCore or LIBCurl error was returned. + LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error from poll request returned from libraries. " << status.toTerseString() << LL_ENDL; + } + else + { + LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error result from LLCoreHttpUtil::HttpCoroHandler. Code " + << status.toTerseString() << ": '" << httpResults["message"] << "'" << LL_ENDL; } - LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error result from LLCoreHttpUtil::HttpCoroHandler. Code " - << status.toTerseString() << ": '" << httpResults["message"] << "'" << LL_ENDL; - if (errorCount < MAX_EVENT_POLL_HTTP_ERRORS) + if (errorCount < MAX_EVENT_POLL_ERRORS) { // An unanticipated error has been received from our poll // request. Calculate a timeout and wait for it to expire(sleep) - // before trying again. The sleep time is increased by 5 seconds + // before trying again. The sleep time is increased by 3 seconds // for each consecutive error. - ++errorCount; F32 waitToRetry = EVENT_POLL_ERROR_RETRY_SECONDS + errorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC; + ++errorCount; + LL_WARNS("LLEventPollImpl") << "<" << counter << "> Retrying in " << waitToRetry << " seconds, error count is now " << errorCount << LL_ENDL; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index f08ef8d24a8..018d4c4bba5 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1067,6 +1067,91 @@ bool LLFace::calcAlignedPlanarTE(const LLFace* align_to, LLVector2* res_st_offs return true; } +F32 dot_product(const LLVector3& a, const LLVector3& b) +{ + return a.mV[VX] * b.mV[VX] + a.mV[VY] * b.mV[VY] + a.mV[VZ] * b.mV[VZ]; +} + +bool LLFace::calcAlignedPlanarGLTF( + const LLFace* align_to, + LLVector2* res_st_offset, + LLVector2* res_st_scale, + F32* res_st_rot, + S32 gltf_info_index) const +{ + if (!align_to) + { + return false; + } + + const LLTextureEntry* orig_tep = align_to->getTextureEntry(); + const LLTextureEntry* tep = getTextureEntry(); + if (!orig_tep || !tep) + { + return false; + } + + // Only support planar mapping for now + if (orig_tep->getTexGen() != LLTextureEntry::TEX_GEN_PLANAR || + tep->getTexGen() != LLTextureEntry::TEX_GEN_PLANAR) + { + return false; + } + + LLGLTFMaterial* orig_mat = orig_tep->getGLTFRenderMaterial(); + LLGLTFMaterial* this_mat = tep->getGLTFRenderMaterial(); + if (!orig_mat || !this_mat) + { + return false; + } + + // Get the original GLTF transform for the specified channel + const auto& orig_tt = orig_mat->mTextureTransform[gltf_info_index]; + + // Convert GLTF transform to legacy TE transform + F32 map_scaleS, map_scaleT, map_offsS, map_offsT, map_rot; + LLGLTFMaterial::convertPBRTransformToTexture( + orig_tt.mScale, + orig_tt.mOffset, + orig_tt.mRotation, + map_scaleS, map_scaleT, map_offsS, map_offsT, map_rot); + + // Calculate aligments + LLVector3 orig_pos, this_pos; + LLQuaternion orig_face_rot, this_face_rot; + F32 orig_proj_scale, this_proj_scale; + align_to->getPlanarProjectedParams(&orig_face_rot, &orig_pos, &orig_proj_scale); + getPlanarProjectedParams(&this_face_rot, &this_pos, &this_proj_scale); + + // The rotation of "this face's" texture: + LLQuaternion orig_st_rot = LLQuaternion(map_rot, LLVector3::z_axis) * orig_face_rot; + LLQuaternion this_st_rot = orig_st_rot * ~this_face_rot; + F32 x_ang, y_ang, z_ang; + this_st_rot.getEulerAngles(&x_ang, &y_ang, &z_ang); + + // Offset and scale of "this face's" texture: + LLVector3 centers_dist = (this_pos - orig_pos) * ~orig_st_rot; + LLVector3 st_scale(map_scaleS, map_scaleT, 1.f); + st_scale *= orig_proj_scale; + centers_dist.scaleVec(st_scale); + LLVector2 orig_st_offset(map_offsS, map_offsT); + + LLVector2 tex_res_st_offset = orig_st_offset + (LLVector2)centers_dist; + tex_res_st_offset.mV[VX] -= (S32)tex_res_st_offset.mV[VX]; + tex_res_st_offset.mV[VY] -= (S32)tex_res_st_offset.mV[VY]; + + st_scale /= this_proj_scale; + + // Convert aligned legacy TE transform back to GLTF transform + LLGLTFMaterial::convertTextureTransformToPBR( + st_scale.mV[0], st_scale.mV[1], + tex_res_st_offset.mV[0], tex_res_st_offset.mV[1], + z_ang, + *res_st_scale, *res_st_offset, *res_st_rot); + + return true; +} + void LLFace::updateRebuildFlags() { if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) @@ -1401,11 +1486,11 @@ bool LLFace::getGeometryVolume(const LLVolume& volume, // They are used only to display a face selection marker // (white square with a rounded cross at the center) const auto& tt = gltf_mat->mTextureTransform[gltf_info_index]; - r = -tt.mRotation * 2; - ms = tt.mScale[VX]; - mt = tt.mScale[VY]; - os += tt.mOffset[VX] + (ms - 1) / 2; - ot -= tt.mOffset[VY] + (mt - 1) / 2; + LLGLTFMaterial::convertPBRTransformToTexture( + tt.mScale, + tt.mOffset, + tt.mRotation, + ms, mt, os, ot, r); } else { @@ -2378,7 +2463,11 @@ F32 LLFace::adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius //the above calculation is too expensive //the below is a good estimation: bounding box of the bounding sphere: - F32 alpha = 0.5f * (radius + screen_radius - d) / radius ; + F32 alpha = 1.f; + if (!is_approx_zero(radius)) // radius can be something like -1e-10 + { + alpha = 0.5f * (radius + screen_radius - d) / radius; + } alpha = llclamp(alpha, 0.f, 1.f) ; return alpha * alpha ; } diff --git a/indra/newview/llface.h b/indra/newview/llface.h index df31e9ea908..6e9d23c3a2d 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -103,6 +103,8 @@ class alignas(16) LLFace LLVector3 getPositionAgent() const; LLVector2 surfaceToTexture(LLVector2 surface_coord, const LLVector4a& position, const LLVector4a& normal); void getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_pos, F32* scale) const; + bool calcAlignedPlanarGLTF(const LLFace* align_to, LLVector2* res_st_offset, + LLVector2* res_st_scale, F32* res_st_rot, S32 gltf_info_index = 0) const; bool calcAlignedPlanarTE(const LLFace* align_to, LLVector2* st_offset, LLVector2* st_scale, F32* st_rot, LLRender::eTexIndex map = LLRender::DIFFUSE_MAP) const; diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm index 6921cd61017..99e93bafbf7 100644 --- a/indra/newview/llfilepicker_mac.mm +++ b/indra/newview/llfilepicker_mac.mm @@ -241,8 +241,13 @@ void doSaveDialogModeless(const std::string* file, NSURL* url = [NSURL fileURLWithPath:fileName]; [panel setNameFieldStringValue: fileName]; - [panel setDirectoryURL: url]; + NSURL *last_url = [[NSUserDefaults standardUserDefaults] URLForKey:@"NSNavLastRootDirectory"]; + if(!last_url) + { + NSURL *downloads_url = [[NSFileManager defaultManager] URLsForDirectory:NSDownloadsDirectory inDomains:NSUserDomainMask].firstObject; + [panel setDirectoryURL:downloads_url]; + } [panel beginWithCompletionHandler:^(NSModalResponse result) { diff --git a/indra/newview/llfloater360capture.cpp b/indra/newview/llfloater360capture.cpp index 95e7b9af41f..ed07d49ac18 100644 --- a/indra/newview/llfloater360capture.cpp +++ b/indra/newview/llfloater360capture.cpp @@ -403,7 +403,7 @@ void LLFloater360Capture::suspendForAFrame() U32 curr_frame_count = LLFrameTimer::getFrameCount(); while (LLFrameTimer::getFrameCount() <= curr_frame_count + frame_count_delta) { - llcoro::suspend(); + llcoro::suspendUntilNextFrame(); } } diff --git a/indra/newview/llfloaterbigpreview.cpp b/indra/newview/llfloaterbigpreview.cpp deleted file mode 100644 index ba682494bb0..00000000000 --- a/indra/newview/llfloaterbigpreview.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/** -* @file llfloaterbigpreview.cpp -* @brief Display of extended (big) preview for snapshots and SL Share -* @author merov@lindenlab.com -* -* $LicenseInfo:firstyear=2013&license=viewerlgpl$ -* Second Life Viewer Source Code -* Copyright (C) 2013, 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 "llfloaterbigpreview.h" -#include "llsnapshotlivepreview.h" - -/////////////////////// -//LLFloaterBigPreview// -/////////////////////// - -LLFloaterBigPreview::LLFloaterBigPreview(const LLSD& key) : LLFloater(key), - mPreviewPlaceholder(NULL), - mFloaterOwner(NULL) -{ -} - -LLFloaterBigPreview::~LLFloaterBigPreview() -{ - if (mPreviewHandle.get()) - { - mPreviewHandle.get()->die(); - } -} - -void LLFloaterBigPreview::onCancel() -{ - closeFloater(); -} - -void LLFloaterBigPreview::closeOnFloaterOwnerClosing(LLFloater* floaterp) -{ - if (isFloaterOwner(floaterp)) - { - closeFloater(); - } -} - -bool LLFloaterBigPreview::postBuild() -{ - mPreviewPlaceholder = getChild("big_preview_placeholder"); - return LLFloater::postBuild(); -} - -void LLFloaterBigPreview::draw() -{ - LLFloater::draw(); - - LLSnapshotLivePreview * previewp = static_cast(mPreviewHandle.get()); - - // Display the preview if one is available - if (previewp && previewp->getBigThumbnailImage()) - { - // Get the preview rect - const LLRect& preview_rect = mPreviewPlaceholder->getRect(); - - // Get the preview texture size - S32 thumbnail_w = previewp->getBigThumbnailWidth(); - S32 thumbnail_h = previewp->getBigThumbnailHeight(); - - // Compute the scaling ratio and the size of the final texture in the rect: we want to prevent anisotropic scaling (distorted in x and y) - F32 ratio = llmax((F32)(thumbnail_w)/(F32)(preview_rect.getWidth()), (F32)(thumbnail_h)/(F32)(preview_rect.getHeight())); - thumbnail_w = (S32)((F32)(thumbnail_w)/ratio); - thumbnail_h = (S32)((F32)(thumbnail_h)/ratio); - - // Compute the preview offset within the preview rect: we want to center that preview in the available rect - const S32 local_offset_x = (preview_rect.getWidth() - thumbnail_w) / 2 ; - const S32 local_offset_y = (preview_rect.getHeight() - thumbnail_h) / 2 ; - - // Compute preview offset within the floater rect - S32 offset_x = preview_rect.mLeft + local_offset_x; - S32 offset_y = preview_rect.mBottom + local_offset_y; - - gGL.matrixMode(LLRender::MM_MODELVIEW); - // Apply floater transparency to the texture unless the floater is focused. - F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); - LLColor4 color = LLColor4::white; - - // Draw the preview texture - gl_draw_scaled_image(offset_x, offset_y, - thumbnail_w, thumbnail_h, - previewp->getBigThumbnailImage(), color % alpha); - } -} - diff --git a/indra/newview/llfloaterbigpreview.h b/indra/newview/llfloaterbigpreview.h deleted file mode 100644 index 1d5804acf5e..00000000000 --- a/indra/newview/llfloaterbigpreview.h +++ /dev/null @@ -1,54 +0,0 @@ -/** -* @file llfloaterbigpreview.h -* @brief Display of extended (big) preview for snapshots -* @author merov@lindenlab.com -* -* $LicenseInfo:firstyear=2013&license=viewerlgpl$ -* Second Life Viewer Source Code -* Copyright (C) 2013, 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_LLFLOATERBIGPREVIEW_H -#define LL_LLFLOATERBIGPREVIEW_H - -#include "llfloater.h" - -class LLFloaterBigPreview : public LLFloater -{ -public: - LLFloaterBigPreview(const LLSD& key); - ~LLFloaterBigPreview(); - - bool postBuild(); - void draw(); - void onCancel(); - - void setPreview(LLView* previewp) { mPreviewHandle = previewp->getHandle(); } - void setFloaterOwner(LLFloater* floaterp) { mFloaterOwner = floaterp; } - bool isFloaterOwner(LLFloater* floaterp) const { return (mFloaterOwner == floaterp); } - void closeOnFloaterOwnerClosing(LLFloater* floaterp); - -private: - LLHandle mPreviewHandle; - LLUICtrl* mPreviewPlaceholder; - LLFloater* mFloaterOwner; -}; - -#endif // LL_LLFLOATERBIGPREVIEW_H - diff --git a/indra/newview/llfloatereditenvironmentbase.cpp b/indra/newview/llfloatereditenvironmentbase.cpp index a42c94f0496..bc1f3045bba 100644 --- a/indra/newview/llfloatereditenvironmentbase.cpp +++ b/indra/newview/llfloatereditenvironmentbase.cpp @@ -262,7 +262,7 @@ void LLFloaterEditEnvironmentBase::onSaveAsCommit(const LLSD& notification, cons } else if (mInventoryItem) { - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); LLUUID parent_id = mInventoryItem->getParentUUID(); if (marketplacelistings_id == parent_id || gInventory.isObjectDescendentOf(mInventoryItem->getUUID(), gInventory.getLibraryRootFolderID())) { diff --git a/indra/newview/llfloaterexperiences.cpp b/indra/newview/llfloaterexperiences.cpp index 999a473a49c..79d74093a27 100644 --- a/indra/newview/llfloaterexperiences.cpp +++ b/indra/newview/llfloaterexperiences.cpp @@ -385,8 +385,11 @@ void LLFloaterExperiences::retrieveExperienceListCoro(std::string url, if (!status) { + LL_WARNS("Experience") << "Failed to retrieve list. Error: " << status.toTerseString() + << ". Type: " << errorNotify << " Message: " << status.getMessage() << LL_ENDL; + LLSD subs; - subs["ERROR_MESSAGE"] = status.getType(); + subs["ERROR_MESSAGE"] = llformat(" %d\n %s", (S32)status.getType(), status.getMessage().c_str()); LLNotificationsUtil::add(errorNotify, subs); return; diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index a0f2dbe1972..5f9d3ac3049 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -57,6 +57,8 @@ #include "llsdserialize.h" #include "llviewermenu.h" // is_agent_mappable #include "llviewerobjectlist.h" +#include "llvoavatar.h" +#include "llnearbyvoicemoderation.h" const S32 EVENTS_PER_IDLE_LOOP_CURRENT_SESSION = 80; @@ -90,6 +92,7 @@ LLFloaterIMContainer::LLFloaterIMContainer(const LLSD& seed, const Params& param mAutoResize = false; LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::IM, this); + LLNearbyVoiceModeration::getInstance(); } LLFloaterIMContainer::~LLFloaterIMContainer() @@ -530,6 +533,33 @@ void LLFloaterIMContainer::idleUpdate() mGeneralTitleInUse = !needs_override; setTitle(needs_override ? conversation_floaterp->getTitle() : mGeneralTitle); } + const LLConversationItem* nearby_session = getSessionModel(LLUUID()); + if (nearby_session) + { + LLSpeakerMgr* speaker_mgr = (LLSpeakerMgr*)(LLLocalSpeakerMgr::getInstance()); + + LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = nearby_session->getChildrenBegin(); + LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = nearby_session->getChildrenEnd(); + while (current_participant_model != end_participant_model) + { + LLConversationItemParticipant* participant_model = + dynamic_cast((*current_participant_model).get()); + if (participant_model) + { + bool show_moderator_options = LLNearbyVoiceModeration::getInstance()->isNearbyChatModerator(); + LLUUID participant_id = participant_model->getUUID(); + if (participant_id != gAgentID) + { + // Don't show moderator options if participant is not connected to the same spatial channel + LLSpeaker* speakerp = speaker_mgr->findSpeaker(participant_id).get(); + show_moderator_options &= speakerp && speakerp->isInVoiceChannel(); + } + participant_model->setModeratorOptionsVisible(show_moderator_options); + } + + current_participant_model++; + } + } } mParticipantRefreshTimer.setTimerExpirySec(1.0f); @@ -1685,6 +1715,10 @@ bool LLFloaterIMContainer::visibleContextMenuItem(const LLSD& userdata) { return isMuted(conversation_item->getUUID()); } + else if ("can_allow_text_chat" == item) + { + return !isNearbyChatSpeakerSelected(); + } return true; } @@ -2014,9 +2048,27 @@ LLConversationViewParticipant* LLFloaterIMContainer::createConversationViewParti bool LLFloaterIMContainer::enableModerateContextMenuItem(const std::string& userdata, bool is_self) { - // only group moderators can perform actions related to this "enable callback" - if (!isGroupModerator()) + if (LLNearbyVoiceModeration::getInstance()->isNearbyChatModerator() && isNearbyChatSpeakerSelected()) { + // Determine here which actions are allowed + if ("can_moderate_voice" == userdata) + { + return true; + } + else if (("can_mute" == userdata)) + { + return !is_self; + } + else if ("can_unmute" == userdata) + { + return true; + } + + return false; + } + else if (!isGroupModerator()) + { + // only group moderators can perform actions related to this "enable callback" return false; } @@ -2149,7 +2201,35 @@ void LLFloaterIMContainer::banSelectedMember(const LLUUID& participant_uuid) void LLFloaterIMContainer::moderateVoice(const std::string& command, const LLUUID& userID) { - if (!gAgent.getRegion()) return; + if (!gAgent.getRegion()) + { + return; + } + + if (isNearbyChatSpeakerSelected()) + { + if ("selected" == command) + { + // Request a mute/unmute using a capability request via the simulator + LLNearbyVoiceModeration::getInstance()->requestMuteIndividual(userID, !isMuted(userID)); + } + else + if ("mute_all" == command) + { + // Send the mute_all request to the server + const bool mute_state = true; + LLNearbyVoiceModeration::getInstance()->requestMuteAll(mute_state); + } + else + if ("unmute_all" == command) + { + // Send the unmute_all request to the server + const bool mute_state = false; + LLNearbyVoiceModeration::getInstance()->requestMuteAll(mute_state); + } + + return; + } if (command.compare("selected")) { @@ -2267,6 +2347,31 @@ LLSpeaker * LLFloaterIMContainer::getSpeakerOfSelectedParticipant(LLSpeakerMgr * return speaker_managerp->findSpeaker(participant_itemp->getUUID()); } +bool LLFloaterIMContainer::isNearbyChatSpeakerSelected() +{ + LLFolderViewItem *selectedItem = mConversationsRoot->getCurSelectedItem(); + if (!selectedItem) + { + LL_WARNS() << "Current selected item is null" << LL_ENDL; + return NULL; + } + + conversations_widgets_map::const_iterator iter = mConversationsWidgets.begin(); + conversations_widgets_map::const_iterator end = mConversationsWidgets.end(); + const LLUUID * conversation_uuidp = NULL; + while(iter != end) + { + if (iter->second == selectedItem || iter->second == selectedItem->getParentFolder()) + { + conversation_uuidp = &iter->first; + break; + } + ++iter; + } + // Nearby chat ID is LLUUID::null + return conversation_uuidp->isNull(); +} + void LLFloaterIMContainer::toggleAllowTextChat(const LLUUID& participant_uuid) { LLIMSpeakerMgr * speaker_managerp = dynamic_cast(getSpeakerMgrForSelectedParticipant()); diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index 30eed8be365..9f1690a9b9c 100644 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -178,6 +178,7 @@ class LLFloaterIMContainer void banSelectedMember(const LLUUID& participant_uuid); void openNearbyChat(); bool isParticipantListExpanded(); + bool isNearbyChatSpeakerSelected(); void idleUpdate(); // for convenience (self) from static idle void idleProcessEvents(); diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index 84a9fad708b..6d642638b3b 100644 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -142,7 +142,7 @@ void LLFloaterIMSession::onClickCloseBtn(bool app_qutting) { if (app_qutting) { - LLFloaterIMSessionTab::onClickCloseBtn(); + LLFloaterIMSessionTab::onClickCloseBtn(app_qutting); return; } diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 65c13797ac3..453161b7928 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -48,6 +48,7 @@ #include "llfloaterimnearbychat.h" #include "llgroupiconctrl.h" #include "lllayoutstack.h" +#include "llnotificationsutil.h" #include "llpanelemojicomplete.h" #include "lltoolbarview.h" @@ -1417,3 +1418,20 @@ bool LLFloaterIMSessionTab::handleKeyHere(KEY key, MASK mask ) } return handled; } + +void LLFloaterIMSessionTab::onClickCloseBtn(bool app_quitting) +{ + bool is_ad_hoc = (mSession ? mSession->isAdHocSessionType() : false); + if (is_ad_hoc && !app_quitting) + { + LLNotificationsUtil::add("ConfirmLeaveAdhoc", LLSD(), LLSD(), [this](const LLSD& notification, const LLSD& response) + { + if (0 == LLNotificationsUtil::getSelectedOption(notification, response)) + closeFloater(); + }); + } + else + { + closeFloater(); + } +} diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h index 6d04d622e18..b27ac1b8f9e 100644 --- a/indra/newview/llfloaterimsessiontab.h +++ b/indra/newview/llfloaterimsessiontab.h @@ -85,6 +85,8 @@ class LLFloaterIMSessionTab void closeFloater(bool app_quitting = false) override; void deleteAllChildren() override; + virtual void onClickCloseBtn(bool app_quitting = false) override; + // Handle the left hand participant list widgets void addConversationViewParticipant(LLConversationItem* item, bool update_view = true); void removeConversationViewParticipant(const LLUUID& participant_id); diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp index c961070787e..33e054aab91 100644 --- a/indra/newview/llfloaterlinkreplace.cpp +++ b/indra/newview/llfloaterlinkreplace.cpp @@ -225,6 +225,21 @@ void LLFloaterLinkReplace::linkCreatedCallback(LLHandle fl << " - description update = " << (needs_description_update ? "true" : "false") << LL_NEWLINE << " - outfit_folder_id = " << outfit_folder_id.asString() << LL_ENDL; + std::string old_description; + if (needs_wearable_ordering_update) + { + LLViewerInventoryItem* old_item = gInventory.getItem(old_item_id); + LLViewerInventoryItem* target_item = gInventory.getItem(target_item_id); + if (old_item && target_item && + old_item->getType() == LLAssetType::AT_CLOTHING && + target_item->getType() == LLAssetType::AT_CLOTHING && + old_item->getWearableType() == target_item->getWearableType()) + { + // Preserve the original description, which contains ordering info + old_description = old_item->getActualDescription(); + } + } + // If we are replacing an object, bodypart or gesture link within an outfit folder, // we need to change the actual description of the link itself. LLAppearanceMgr *should* // have created COF links that will be used to save the outfit with an empty description. @@ -246,7 +261,14 @@ void LLFloaterLinkReplace::linkCreatedCallback(LLHandle fl { LLPointer item = *it; - if ((item->getType() == LLAssetType::AT_BODYPART || + if (item->getType() == LLAssetType::AT_CLOTHING && !old_description.empty()) + { + // Use the old description to set ordering info + LLSD updates; + updates["desc"] = old_description; + update_inventory_item(item->getUUID(), updates, LLPointer(NULL)); + } + else if ((item->getType() == LLAssetType::AT_BODYPART || item->getType() == LLAssetType::AT_OBJECT || item->getType() == LLAssetType::AT_GESTURE) && !item->getActualDescription().empty()) @@ -347,12 +369,9 @@ void LLFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items) bool is_outfit_folder = gInventory.isObjectDescendentOf(source_item->getParentUUID(), outfit_folder_id); // If either the new or old item in the COF is a wearable, we need to update wearable ordering after the link has been replaced bool needs_wearable_ordering_update = (is_outfit_folder && source_item->getType() == LLAssetType::AT_CLOTHING) || target_item->getType() == LLAssetType::AT_CLOTHING; - // Other items in the COF need a description update (description of the actual link item must be empty) - bool needs_description_update = is_outfit_folder && target_item->getType() != LLAssetType::AT_CLOTHING; LL_DEBUGS() << "is_outfit_folder = " << (is_outfit_folder ? "true" : "false") << LL_NEWLINE - << "needs_wearable_ordering_update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_NEWLINE - << "needs_description_update = " << (needs_description_update ? "true" : "false") << LL_ENDL; + << "needs_wearable_ordering_update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_ENDL; LLInventoryObject::const_object_list_t obj_array; obj_array.push_back(LLConstPointer(target_item)); @@ -361,7 +380,7 @@ void LLFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items) source_item->getUUID(), target_item->getUUID(), needs_wearable_ordering_update, - needs_description_update, + is_outfit_folder, (is_outfit_folder ? source_item->getParentUUID() : LLUUID::null) )); link_inventory_array(source_item->getParentUUID(), obj_array, cb); } diff --git a/indra/newview/llfloatermarketplace.cpp b/indra/newview/llfloatermarketplace.cpp index 7316d7617dd..bb2378d8643 100644 --- a/indra/newview/llfloatermarketplace.cpp +++ b/indra/newview/llfloatermarketplace.cpp @@ -39,6 +39,27 @@ LLFloaterMarketplace::~LLFloaterMarketplace() { } +void LLFloaterMarketplace::onOpen(const LLSD& key) +{ + Params params(key); + + if (!params.validateBlock()) + { + closeFloater(); + return; + } + + if (params.url().empty()) + { + openMarketplace(); + } + else + { + openMarketplaceURL(params.url); + set_current_url(params.url); // Fix looping back to previous url when using the viewer navigation bar + } +} + // just to override LLFloaterWebContent void LLFloaterMarketplace::onClose(bool app_quitting) { @@ -68,3 +89,18 @@ void LLFloaterMarketplace::openMarketplace() mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML); } } + +void LLFloaterMarketplace::openMarketplaceURL(const std::string& url) +{ + if (mCurrentURL != url) + { + mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML); + } +} + +// static +bool LLFloaterMarketplace::isMarketplaceURL(const std::string& url) +{ + static LLCachedControl marketplace_url(gSavedSettings, "MarketplaceURL", "https://marketplace.secondlife.com/"); + return url.starts_with(marketplace_url()); +} diff --git a/indra/newview/llfloatermarketplace.h b/indra/newview/llfloatermarketplace.h index 9524c94eeec..17979dae90b 100644 --- a/indra/newview/llfloatermarketplace.h +++ b/indra/newview/llfloatermarketplace.h @@ -36,11 +36,14 @@ class LLFloaterMarketplace: public: void openMarketplace(); + void openMarketplaceURL(const std::string& url); + bool static isMarketplaceURL(const std::string& url); private: LLFloaterMarketplace(const LLSD& key); ~LLFloaterMarketplace(); bool postBuild() override; + void onOpen(const LLSD& key) override; void onClose(bool app_quitting) override; }; diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index f20fea01c59..dfd023e424b 100644 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -29,6 +29,7 @@ #include "llfloatermarketplacelistings.h" +#include "llcallbacklist.h" #include "llfloaterreg.h" #include "llfiltereditor.h" #include "llfolderview.h" @@ -231,7 +232,7 @@ void LLPanelMarketplaceListings::onTabChange() void LLPanelMarketplaceListings::onAddButtonClicked() { - LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + LLUUID marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); llassert(marketplacelistings_id.notNull()); LLFolderType::EType preferred_type = LLFolderType::lookup("category"); LLHandle handle = getHandle(); @@ -351,7 +352,15 @@ class LLMarketplaceListingsAddedObserver : public LLInventoryCategoryAddedObserv if (added_category_type == LLFolderType::FT_MARKETPLACE_LISTINGS) { - mMarketplaceListingsFloater->initializeMarketPlace(); + LLHandle handle = mMarketplaceListingsFloater->getHandle(); + doOnIdleOneTime([handle]() + { + LLFloaterMarketplaceListings* floater = (LLFloaterMarketplaceListings*)handle.get(); + if (floater) + { + floater->initializeMarketPlace(); + } + }); } } } @@ -415,7 +424,7 @@ bool LLFloaterMarketplaceListings::postBuild() // Fetch aggressively so we can interact with listings as soon as possible if (!fetchContents()) { - const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); LLInventoryModelBackgroundFetch::instance().start(marketplacelistings_id, true); } @@ -513,8 +522,6 @@ void LLFloaterMarketplaceListings::setRootFolder() return; } - mRootFolderCreating = false; - // No longer need to observe new category creation if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) { @@ -524,6 +531,8 @@ void LLFloaterMarketplaceListings::setRootFolder() } llassert(!mCategoryAddedObserver); + mRootFolderCreating = false; + if (marketplacelistings_id == mRootFolderId) { LL_WARNS("SLM") << "Inventory warning: Marketplace listings folder already set" << LL_ENDL; @@ -566,7 +575,8 @@ void LLFloaterMarketplaceListings::setPanels() void LLFloaterMarketplaceListings::initializeMarketPlace() { - LLMarketplaceData::instance().initializeSLM(boost::bind(&LLFloaterMarketplaceListings::updateView, this)); + if (!mRootFolderCreating) + LLMarketplaceData::instance().initializeSLM(boost::bind(&LLFloaterMarketplaceListings::updateView, this)); } S32 LLFloaterMarketplaceListings::getFolderCount() @@ -909,7 +919,7 @@ void LLFloaterMarketplaceValidation::onOpen(const LLSD& key) LLUUID cat_id(key.asUUID()); if (cat_id.isNull()) { - cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + cat_id = gInventory.getMarketplaceListingsUUID(); } // Validates the folder diff --git a/indra/newview/llfloaterobjectweights.cpp b/indra/newview/llfloaterobjectweights.cpp index fa491a4b279..bd8530abd7e 100644 --- a/indra/newview/llfloaterobjectweights.cpp +++ b/indra/newview/llfloaterobjectweights.cpp @@ -208,7 +208,7 @@ void LLFloaterObjectWeights::draw() toggleRenderLoadingIndicators(false); } mTrianglesShown->setText(llformat("%d", total_tris)); - mPixelArea->setText(llformat("%d", pixel_area)); + mPixelArea->setText(llformat("%ld", (S64)pixel_area)); // value capped at 10M } LLFloater::draw(); } diff --git a/indra/newview/llfloaterpay.cpp b/indra/newview/llfloaterpay.cpp index d5e45c09e30..e497fb09149 100644 --- a/indra/newview/llfloaterpay.cpp +++ b/indra/newview/llfloaterpay.cpp @@ -502,7 +502,7 @@ void LLFloaterPay::onGive(give_money_ptr info) amount = atoi(text_field->getValue().asString().c_str()); } - if (amount > PAY_AMOUNT_NOTIFICATION && gStatusBar && gStatusBar->getBalance() > amount) + if (amount > PAY_AMOUNT_NOTIFICATION) { LLUUID payee_id = LLUUID::null; bool is_group = false; 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/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 6e27fd694a5..537dca99da4 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -474,7 +474,8 @@ bool LLFloaterPreference::postBuild() getChild("log_path_string")->setEnabled(false); // make it read-only but selectable - getChild("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); + mLanguageCombobox = getChild("language_combobox"); + mLanguageCombobox->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); mTimeFormatCombobox = getChild("time_format_combobox"); mTimeFormatCombobox->setCommitCallback(boost::bind(&LLFloaterPreference::onTimeFormatChange, this)); @@ -516,18 +517,18 @@ bool LLFloaterPreference::postBuild() std::map::iterator iter = labels.find(system_lang); if (iter != labels.end()) { - getChild("language_combobox")->add(iter->second, LLSD("default"), ADD_TOP, true); + mLanguageCombobox->add(iter->second, LLSD("default"), ADD_TOP, true); } else { LL_WARNS() << "Language \"" << system_lang << "\" is not in default_languages.xml" << LL_ENDL; - getChild("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); + mLanguageCombobox->add("System default", LLSD("default"), ADD_TOP, true); } } else { LL_WARNS() << "Failed to load labels from " << user_filename << ". Using default." << LL_ENDL; - getChild("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); + mLanguageCombobox->add("System default", LLSD("default"), ADD_TOP, true); } #ifndef LL_DISCORD @@ -619,8 +620,6 @@ void LLFloaterPreference::apply() std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); setCacheLocation(cache_location); - LLViewerMedia::getInstance()->setCookiesEnabled(getChild("cookies_enabled")->getValue()); - if (hasChild("web_proxy_enabled", true) &&hasChild("web_proxy_editor", true) && hasChild("web_proxy_port", true)) { bool proxy_enable = getChild("web_proxy_enabled")->getValue(); @@ -1340,6 +1339,12 @@ void LLFloaterPreference::refresh() updateClickActionViews(); mTimeFormatCombobox->selectByValue(gSavedSettings.getBOOL("Use24HourClock") ? "1" : "0"); + + std::string current_language = gSavedSettings.getString("Language"); + if (current_language != "default" && !current_language.empty()) + { + mLanguageCombobox->selectByValue(LLSD(current_language)); + } } void LLFloaterPreference::onCommitWindowedMode() diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index a2aa3ee8de0..3028bec64a1 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -237,6 +237,7 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver, LLButton* mEnablePopupBtn = nullptr; LLButton* mDisablePopupBtn = nullptr; LLComboBox* mTimeFormatCombobox = nullptr; + LLComboBox* mLanguageCombobox = nullptr; std::unique_ptr< ll::prefs::SearchData > mSearchData; bool mSearchDataDirty; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 4cb6e7be964..1b5566a32dc 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -538,6 +538,18 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) panel->getChildView("access_combo")->setEnabled(gAgent.isGodlike() || (region && region->canManageEstate() && !teen_grid)); panel->setCtrlsEnabled(allow_modify); + panel->getChild("estate_id")->setValue((S32)region_info.mEstateID); + + if (region) + { + panel->getChild("grid_position_x")->setValue((S32)(region->getOriginGlobal()[VX] / 256)); + panel->getChild("grid_position_y")->setValue((S32)(region->getOriginGlobal()[VY] / 256)); + } + else + { + panel->getChild("grid_position_x")->setDefaultText(); + panel->getChild("grid_position_y")->setDefaultText(); + } // DEBUG PANEL panel = tab->getChild("Debug"); @@ -902,6 +914,9 @@ bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region) getChildView("apply_btn")->setEnabled(false); getChildView("access_text")->setEnabled(allow_modify); // getChildView("access_combo")->setEnabled(allow_modify); + getChildView("estate_id")->setEnabled(false); + getChildView("grid_position_x")->setEnabled(false); + getChildView("grid_position_y")->setEnabled(false); // now set in processRegionInfo for teen grid detection getChildView("kick_btn")->setEnabled(allow_modify); getChildView("kick_all_btn")->setEnabled(allow_modify); diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 9b7a4e5134d..3c84f5b4599 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -123,19 +123,32 @@ void LLFloaterSearch::initiateSearch(const LLSD& tokens) subs["COLLECTION"] = ""; if (subs["TYPE"] == "standard") { + std::string collection_args; if (mCollectionType.find(collection) != mCollectionType.end()) { - subs["COLLECTION"] = "&collection_chosen=" + std::string(collection); + collection_args = "&collection_chosen=" + std::string(collection); } - else + else if (tokens.has("collections") && tokens["collections"].isArray()) + { + const LLSD &sd = tokens["collections"]; + for (LLSD::array_const_iterator it = sd.beginArray(); + it != sd.endArray(); + ++it) + { + if (mCollectionType.find(it->asString()) != mCollectionType.end()) + { + collection_args += "&collection_chosen=" + std::string(*it); + } + } + } + if (collection_args.empty()) { - std::string collection_args(""); for (std::set::iterator it = mCollectionType.begin(); it != mCollectionType.end(); ++it) { collection_args += "&collection_chosen=" + std::string(*it); } - subs["COLLECTION"] = collection_args; } + subs["COLLECTION"] = collection_args; } // Default to PG diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index faf7ed0d8c7..83d7a928469 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -1043,7 +1043,7 @@ bool LLFloaterSnapshot::postBuild() getChild("profile_size_combo")->selectNthItem(0); getChild("postcard_size_combo")->selectNthItem(0); getChild("texture_size_combo")->selectNthItem(0); - getChild("local_size_combo")->selectNthItem(8); + getChild("local_size_combo")->selectNthItem(0); getChild("local_format_combo")->selectNthItem(0); impl->mPreviewHandle = previewp->getHandle(); diff --git a/indra/newview/llfloatersounddevices.cpp b/indra/newview/llfloatersounddevices.cpp deleted file mode 100644 index f11c5c0ad8a..00000000000 --- a/indra/newview/llfloatersounddevices.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @file llfloatersounddevices.cpp - * @author Leyla Farazha - * @brief Sound Preferences used for minimal skin - * -* $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#include "llviewerprecompiledheaders.h" - -#include "llfloatersounddevices.h" - -#include "lldraghandle.h" - -#include "llpanelvoicedevicesettings.h" - -// Library includes -#include "indra_constants.h" - -// protected -LLFloaterSoundDevices::LLFloaterSoundDevices(const LLSD& key) -: LLTransientDockableFloater(NULL, false, key) -{ - LLTransientFloaterMgr::getInstance()->addControlView(this); - - // force docked state since this floater doesn't save it between recreations - setDocked(true); -} - -LLFloaterSoundDevices::~LLFloaterSoundDevices() -{ - LLTransientFloaterMgr::getInstance()->removeControlView(this); -} - -// virtual -bool LLFloaterSoundDevices::postBuild() -{ - LLTransientDockableFloater::postBuild(); - - updateTransparency(TT_ACTIVE); // force using active floater transparency (STORM-730) - - LLPanelVoiceDeviceSettings* panel = findChild("device_settings_panel"); - if (panel) - { - panel->setUseTuningMode(false); - getChild("voice_input_device")->setCommitCallback(boost::bind(&LLPanelVoiceDeviceSettings::apply, panel)); - getChild("voice_output_device")->setCommitCallback(boost::bind(&LLPanelVoiceDeviceSettings::apply, panel)); - getChild("mic_volume_slider")->setCommitCallback(boost::bind(&LLPanelVoiceDeviceSettings::apply, panel)); - } - return true; -} - -//virtual -void LLFloaterSoundDevices::setDocked(bool docked, bool pop_on_undock/* = true*/) -{ - LLTransientDockableFloater::setDocked(docked, pop_on_undock); -} - -// virtual -void LLFloaterSoundDevices::setFocus(bool b) -{ - LLTransientDockableFloater::setFocus(b); - - // Force using active floater transparency - // We have to override setFocus() for because selecting an item of the - // combobox causes the floater to lose focus and thus become transparent. - updateTransparency(TT_ACTIVE); -} diff --git a/indra/newview/llfloatervoiceeffect.cpp b/indra/newview/llfloatervoiceeffect.cpp deleted file mode 100644 index 9f7c9aba878..00000000000 --- a/indra/newview/llfloatervoiceeffect.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/** - * @file llfloatervoiceeffect.cpp - * @author Aimee - * @brief Selection and preview of voice effect. - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloatervoiceeffect.h" - -#include "llscrolllistctrl.h" -#include "lltrans.h" -#include "llweb.h" - -LLFloaterVoiceEffect::LLFloaterVoiceEffect(const LLSD& key) - : LLFloater(key) -{ - mCommitCallbackRegistrar.add("VoiceEffect.Record", boost::bind(&LLFloaterVoiceEffect::onClickRecord, this)); - mCommitCallbackRegistrar.add("VoiceEffect.Play", boost::bind(&LLFloaterVoiceEffect::onClickPlay, this)); - mCommitCallbackRegistrar.add("VoiceEffect.Stop", boost::bind(&LLFloaterVoiceEffect::onClickStop, this)); -// mCommitCallbackRegistrar.add("VoiceEffect.Activate", boost::bind(&LLFloaterVoiceEffect::onClickActivate, this)); -} - -// virtual -LLFloaterVoiceEffect::~LLFloaterVoiceEffect() -{ - if(LLVoiceClient::instanceExists()) - { - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (effect_interface) - { - effect_interface->removeObserver(this); - } - } -} - -// virtual -bool LLFloaterVoiceEffect::postBuild() -{ - setDefaultBtn("record_btn"); - getChild("record_btn")->setFocus(true); - getChild("voice_morphing_link")->setTextArg("[URL]", LLTrans::getString("voice_morphing_url")); - - mVoiceEffectList = getChild("voice_effect_list"); - if (mVoiceEffectList) - { - mVoiceEffectList->setCommitCallback(boost::bind(&LLFloaterVoiceEffect::onClickPlay, this)); -// mVoiceEffectList->setDoubleClickCallback(boost::bind(&LLFloaterVoiceEffect::onClickActivate, this)); - } - - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (effect_interface) - { - effect_interface->addObserver(this); - - // Disconnect from the current voice channel ready to record a voice sample for previewing - effect_interface->enablePreviewBuffer(true); - } - - refreshEffectList(); - updateControls(); - - return true; -} - -// virtual -void LLFloaterVoiceEffect::onClose(bool app_quitting) -{ - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (effect_interface) - { - effect_interface->enablePreviewBuffer(false); - } -} - -void LLFloaterVoiceEffect::refreshEffectList() -{ - if (!mVoiceEffectList) - { - return; - } - - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (!effect_interface) - { - mVoiceEffectList->setEnabled(false); - return; - } - - LL_DEBUGS("Voice")<< "Rebuilding Voice Morph list."<< LL_ENDL; - - // Preserve selected items and scroll position - S32 scroll_pos = mVoiceEffectList->getScrollPos(); - uuid_vec_t selected_items; - std::vector items = mVoiceEffectList->getAllSelected(); - for(std::vector::const_iterator it = items.begin(); it != items.end(); it++) - { - selected_items.push_back((*it)->getUUID()); - } - - mVoiceEffectList->deleteAllItems(); - - { - // Add the "No Voice Morph" entry - LLSD element; - - element["id"] = LLUUID::null; - element["columns"][NAME_COLUMN]["column"] = "name"; - element["columns"][NAME_COLUMN]["value"] = getString("no_voice_effect"); - element["columns"][NAME_COLUMN]["font"]["style"] = "BOLD"; - - LLScrollListItem* sl_item = mVoiceEffectList->addElement(element, ADD_BOTTOM); - // *HACK: Copied from llfloatergesture.cpp : ["font"]["style"] does not affect font style :( - if(sl_item) - { - ((LLScrollListText*)sl_item->getColumn(0))->setFontStyle(LLFontGL::BOLD); - } - } - - // Add each Voice Morph template, if there are any (template list includes all usable effects) - const voice_effect_list_t& template_list = effect_interface->getVoiceEffectTemplateList(); - if (!template_list.empty()) - { - for (voice_effect_list_t::const_iterator it = template_list.begin(); it != template_list.end(); ++it) - { - const LLUUID& effect_id = it->second; - - std::string localized_effect = "effect_" + it->first; - std::string effect_name = hasString(localized_effect) ? getString(localized_effect) : it->first; // XML contains localized effects names - - LLSD effect_properties = effect_interface->getVoiceEffectProperties(effect_id); - - // Tag the active effect. - if (effect_id == LLVoiceClient::instance().getVoiceEffectDefault()) - { - effect_name += " " + getString("active_voice_effect"); - } - - // Tag available effects that are new this session - if (effect_properties["is_new"].asBoolean()) - { - effect_name += " " + getString("new_voice_effect"); - } - - LLDate expiry_date = effect_properties["expiry_date"].asDate(); - bool is_template_only = effect_properties["template_only"].asBoolean(); - - std::string font_style = "NORMAL"; - if (!is_template_only) - { - font_style = "BOLD"; - } - - LLSD element; - element["id"] = effect_id; - - element["columns"][NAME_COLUMN]["column"] = "name"; - element["columns"][NAME_COLUMN]["value"] = effect_name; - element["columns"][NAME_COLUMN]["font"]["style"] = font_style; - - element["columns"][1]["column"] = "expires"; - if (!is_template_only) - { - element["columns"][DATE_COLUMN]["value"] = expiry_date; - element["columns"][DATE_COLUMN]["type"] = "date"; - } - else { - element["columns"][DATE_COLUMN]["value"] = getString("unsubscribed_voice_effect"); - } -// element["columns"][DATE_COLUMN]["font"]["style"] = "NORMAL"; - - LLScrollListItem* sl_item = mVoiceEffectList->addElement(element, ADD_BOTTOM); - // *HACK: Copied from llfloatergesture.cpp : ["font"]["style"] does not affect font style :( - if(sl_item) - { - LLFontGL::StyleFlags style = is_template_only ? LLFontGL::NORMAL : LLFontGL::BOLD; - LLScrollListText* slt = dynamic_cast(sl_item->getColumn(0)); - llassert(slt); - if (slt) - { - slt->setFontStyle(style); - } - } - } - } - - // Re-select items that were selected before, and restore the scroll position - for(uuid_vec_t::iterator it = selected_items.begin(); it != selected_items.end(); it++) - { - mVoiceEffectList->selectByID(*it); - } - mVoiceEffectList->setScrollPos(scroll_pos); - mVoiceEffectList->setEnabled(true); -} - -void LLFloaterVoiceEffect::updateControls() -{ - bool recording = false; - - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (effect_interface) - { - recording = effect_interface->isPreviewRecording(); - } - - getChild("record_btn")->setVisible(!recording); - getChild("record_stop_btn")->setVisible(recording); -} - -// virtual -void LLFloaterVoiceEffect::onVoiceEffectChanged(bool effect_list_updated) -{ - if (effect_list_updated) - { - refreshEffectList(); - } - updateControls(); -} - -void LLFloaterVoiceEffect::onClickRecord() -{ - LL_DEBUGS("Voice") << "Record clicked" << LL_ENDL; - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (effect_interface) - { - effect_interface->recordPreviewBuffer(); - } - updateControls(); -} - -void LLFloaterVoiceEffect::onClickPlay() -{ - LL_DEBUGS("Voice") << "Play clicked" << LL_ENDL; - if (!mVoiceEffectList) - { - return; - } - - const LLUUID& effect_id = mVoiceEffectList->getCurrentID(); - - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (effect_interface) - { - effect_interface->playPreviewBuffer(effect_id); - } - updateControls(); -} - -void LLFloaterVoiceEffect::onClickStop() -{ - LL_DEBUGS("Voice") << "Stop clicked" << LL_ENDL; - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (effect_interface) - { - effect_interface->stopPreviewBuffer(); - } - updateControls(); -} - -//void LLFloaterVoiceEffect::onClickActivate() -//{ -// LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); -// if (effect_interface && mVoiceEffectList) -// { -// effect_interface->setVoiceEffect(mVoiceEffectList->getCurrentID()); -// } -//} - diff --git a/indra/newview/llfloatervoiceeffect.h b/indra/newview/llfloatervoiceeffect.h deleted file mode 100644 index 323beb64ae7..00000000000 --- a/indra/newview/llfloatervoiceeffect.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file llfloatervoiceeffect.h - * @author Aimee - * @brief Selection and preview of voice effects. - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLFLOATERVOICEEFFECT_H -#define LL_LLFLOATERVOICEEFFECT_H - -#include "llfloater.h" -#include "llvoiceclient.h" - -class LLButton; -class LLScrollListCtrl; - -class LLFloaterVoiceEffect - : public LLFloater - , public LLVoiceEffectObserver -{ -public: - LOG_CLASS(LLFloaterVoiceEffect); - - LLFloaterVoiceEffect(const LLSD& key); - virtual ~LLFloaterVoiceEffect(); - - bool postBuild() override; - void onClose(bool app_quitting) override; - -private: - enum ColumnIndex - { - NAME_COLUMN = 0, - DATE_COLUMN = 1, - }; - - void refreshEffectList(); - void updateControls(); - - /// Called by voice effect provider when voice effect list is changed. - virtual void onVoiceEffectChanged(bool effect_list_updated) override; - - void onClickRecord(); - void onClickPlay(); - void onClickStop(); -// void onClickActivate(); - - LLUUID mSelectedID; - LLScrollListCtrl* mVoiceEffectList; -}; - -#endif diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp index ac8477a615d..b7844197807 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -170,7 +170,7 @@ namespace void LLGLTFMaterialList::applyOverrideMessage(LLMessageSystem* msg, const std::string& data_in) { - std::istringstream str(data_in); + boost::iostreams::stream str(data_in.data(), data_in.size()); LLSD data; diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 7659e5f082d..074cda1683a 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -317,7 +317,7 @@ void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LL // virtual bool LLGroupList::handleEvent(LLPointer event, const LLSD& userdata) { - // Why is "new group" sufficient? + // "new group" is sufficient because update_group_floaters always calls that on group changes if (event->desc() == "new group") { setDirty(); diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp index 11f049564aa..4327d281e58 100644 --- a/indra/newview/llhudnametag.cpp +++ b/indra/newview/llhudnametag.cpp @@ -301,7 +301,7 @@ void LLHUDNameTag::renderText() const S32 label_height = ll_round((mFontp->getLineHeight() * (F32)mLabelSegments.size() + (VERTICAL_PADDING / 3.f))); label_top_rect.mBottom = label_top_rect.mTop - label_height; LLColor4 label_top_color = text_color; - label_top_color.mV[VALPHA] = gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor; + label_top_color.mV[VALPHA] = bubble_opacity() * alpha_factor; mRoundedRectTopImgp->draw3D(render_position, x_pixel_vec, y_pixel_vec, label_top_rect, label_top_color); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index aa884b8e9f1..b4cce02bdac 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -336,7 +336,7 @@ bool LLInvFVBridge::cutToClipboard() const LLInventoryObject* obj = gInventory.getObject(mUUID); if (obj && isItemMovable() && isItemRemovable()) { - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID &marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); const bool cut_from_marketplacelistings = gInventory.isObjectDescendentOf(mUUID, marketplacelistings_id); if (cut_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(mUUID) || @@ -1378,7 +1378,7 @@ bool LLInvFVBridge::isInboxFolder() const bool LLInvFVBridge::isMarketplaceListingsFolder() const { - const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID folder_id = gInventory.getMarketplaceListingsUUID(); if (folder_id.isNull()) { @@ -1686,7 +1686,7 @@ bool LLInvFVBridge::canListOnMarketplaceNow() const { std::string error_msg; LLInventoryModel* model = getInventoryModel(); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID &marketplacelistings_id = model->getMarketplaceListingsUUID(); if (marketplacelistings_id.notNull()) { LLViewerInventoryCategory * master_folder = model->getCategory(marketplacelistings_id); @@ -1845,7 +1845,7 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) { LLInventoryItem* itemp = model->getItem(mUUID); if (!itemp) return; - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = model->getMarketplaceListingsUUID(); // Note: For a single item, if it's not a copy, then it's a move move_item_to_marketplacelistings(itemp, marketplacelistings_id, ("copy_to_marketplace_listings" == action)); } @@ -2685,7 +2685,7 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, const LLUUID &cat_id = inv_cat->getUUID(); const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = model->getMarketplaceListingsUUID(); const LLUUID from_folder_uuid = inv_cat->getParentUUID(); const bool move_is_into_current_outfit = (mUUID == current_outfit_id); @@ -3765,7 +3765,7 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) { LLInventoryCategory * cat = gInventory.getCategory(mUUID); if (!cat) return; - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = model->getMarketplaceListingsUUID(); move_folder_to_marketplacelistings(cat, marketplacelistings_id, ("move_to_marketplace_listings" != action), (("copy_or_move_to_marketplace_listings" == action))); } else if ("copy_folder_uuid" == action) @@ -4019,7 +4019,7 @@ void LLFolderBridge::pasteFromClipboard() LLInventoryModel* model = getInventoryModel(); if (model && isClipboardPasteable()) { - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID &marketplacelistings_id = model->getMarketplaceListingsUUID(); const bool paste_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); bool cut_from_marketplacelistings = false; @@ -4081,7 +4081,7 @@ void LLFolderBridge::perform_pasteFromClipboard() if (model && isClipboardPasteable()) { const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = model->getMarketplaceListingsUUID(); const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); @@ -4378,7 +4378,7 @@ void LLFolderBridge::pasteLinkFromClipboard() if(model) { const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = model->getMarketplaceListingsUUID(); const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); const bool move_is_into_current_outfit = (mUUID == current_outfit_id); @@ -4478,7 +4478,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); const LLUUID &favorites = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplace_listings_id = model->getMarketplaceListingsUUID(); const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); if (outfits_id == mUUID) @@ -5715,7 +5715,7 @@ bool LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = model->getMarketplaceListingsUUID(); const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); const LLUUID from_folder_uuid = inv_item->getParentUUID(); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 3cc57e851f1..7522ea49079 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -405,7 +405,7 @@ void update_all_marketplace_count(const LLUUID& cat_id) void update_all_marketplace_count() { // Get the marketplace root and launch the recursive exploration - const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID marketplace_listings_uuid = gInventory.getMarketplaceListingsUUID(); if (!marketplace_listings_uuid.isNull()) { update_all_marketplace_count(marketplace_listings_uuid); @@ -1050,11 +1050,7 @@ void open_marketplace_listings() S32 depth_nesting_in_marketplace(LLUUID cur_uuid) { - // Get the marketplace listings root, exit with -1 (i.e. not under the marketplace listings root) if none - // Todo: findCategoryUUIDForType is somewhat expensive with large - // flat root folders yet we use depth_nesting_in_marketplace at - // every turn, find a way to correctly cache this id. - const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID marketplace_listings_uuid = gInventory.getMarketplaceListingsUUID(); if (marketplace_listings_uuid.isNull()) { return -1; @@ -2559,7 +2555,7 @@ bool get_is_favorite(const LLUUID& obj_id) return obj && obj->getIsFavorite(); } - return object->getIsFavorite(); + return object && object->getIsFavorite(); } void set_favorite(const LLUUID& obj_id, bool favorite) @@ -3420,7 +3416,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root if ("delete" == action) { - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID &marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); bool marketplacelistings_item = false; bool has_worn = false; bool needs_replacement = false; @@ -3601,7 +3597,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root if (action == "wear" || action == "wear_add") { const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID mp_id = gInventory.getMarketplaceListingsUUID(); std::copy_if(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids), @@ -4011,7 +4007,7 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root) // target listing *and* the original listing. So we need to keep track of both. // Note: do not however put the marketplace listings root itself in this list or the whole marketplace data will be rebuilt. sMarketplaceFolders.clear(); - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); if (marketplacelistings_id.isNull()) { return; diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index f77088e0b16..24b0866041e 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -1726,7 +1726,7 @@ bool is_category_removable(const LLUUID& folder_id, bool check_worn) } } - const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID mp_id = gInventory.getMarketplaceListingsUUID(); if (mp_id.notNull() && gInventory.isObjectDescendentOf(folder_id, mp_id)) { return false; @@ -1768,7 +1768,7 @@ void LLInventoryGallery::paste() return; } - const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); if (mSelectedItemIDs.size() == 1 && gInventory.isObjectDescendentOf(*mSelectedItemIDs.begin(), marketplacelistings_id)) { return; @@ -2114,7 +2114,7 @@ void LLInventoryGallery::pasteAsLink() } const LLUUID& current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); const LLUUID& my_outifts_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); std::vector objects; @@ -3333,7 +3333,7 @@ bool dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, bool drop, const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = model->getMarketplaceListingsUUID(); const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); const bool move_is_into_current_outfit = (folder_id == current_outfit_id); @@ -3727,7 +3727,7 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, const LLUUID &cat_id = inv_cat->getUUID(); const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = model->getMarketplaceListingsUUID(); //const LLUUID from_folder_uuid = inv_cat->getParentUUID(); const bool move_is_into_current_outfit = (dest_id == current_outfit_id); const bool move_is_into_marketplacelistings = model->isObjectDescendentOf(dest_id, marketplacelistings_id); diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 2576da0a755..1fe29657843 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -407,7 +407,7 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata) if (can_copy) { - const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); if (itemp) { move_item_to_marketplacelistings(itemp, marketplacelistings_id, copy_operation); @@ -426,7 +426,7 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata) // option == 0 Move no copy item(s) // option == 1 Don't move no copy item(s) (leave them behind) bool copy_and_move = option == 0; - const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); // main inventory only allows one item? LLViewerInventoryItem* itemp = gInventory.getItem(lamdba_list.front()); @@ -542,7 +542,7 @@ bool can_list_on_marketplace(const LLUUID &id) if (can_list) { std::string error_msg; - const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); if (marketplacelistings_id.notNull()) { LLViewerInventoryCategory* master_folder = gInventory.getCategory(marketplacelistings_id); @@ -1040,7 +1040,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men // Marketplace bool can_list = false; - const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); if (marketplacelistings_id.notNull() && !is_inbox && !obj->getIsLinkType()) { if (is_folder) diff --git a/indra/newview/llinventorylistitem.cpp b/indra/newview/llinventorylistitem.cpp index a435a4f7c7c..aa6ba6d0238 100644 --- a/indra/newview/llinventorylistitem.cpp +++ b/indra/newview/llinventorylistitem.cpp @@ -41,7 +41,7 @@ #include "llinventorymodel.h" #include "llviewerinventory.h" -static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelInventoryListItemBaseParams(&typeid(LLPanelInventoryListItemBase::Params), "inventory_list_item"); +static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelInventoryListItemBaseParams(typeid(LLPanelInventoryListItemBase::Params), "inventory_list_item"); constexpr S32 WIDGET_SPACING = 3; constexpr S32 FAVORITE_IMAGE_SIZE = 14; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 043fd7003d6..c2f9c483c0f 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -975,6 +975,15 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getLibraryRootFolderID()); } +const LLUUID LLInventoryModel::getMarketplaceListingsUUID() +{ + if (mMarketplaceListingsUUID.isNull()) + { + mMarketplaceListingsUUID = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + } + return mMarketplaceListingsUUID; +} + // Convenience function to create a new category. You could call // updateCategory() with a newly generated UUID category, but this // version will take care of details like what the name should be @@ -1692,7 +1701,7 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 mask |= LLInventoryObserver::LABEL; } // Under marketplace, category labels are quite complex and need extra upate - const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID marketplace_id = getMarketplaceListingsUUID(); if (marketplace_id.notNull() && isObjectDescendentOf(cat->getUUID(), marketplace_id)) { mask |= LLInventoryObserver::LABEL; @@ -3416,6 +3425,7 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, LLSD inventory; if (!is_cache_obsolete) { + LL_PROFILE_ZONE_NAMED("inventory load from file - llsd parse"); LLPointer parser = new LLSDBinaryParser(); if (parser->parse(file, inventory, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) @@ -3427,56 +3437,61 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, if (!is_cache_obsolete) { - const LLSD& llsd_cats = inventory["categories"]; - if (llsd_cats.isArray()) { - LLSD::array_const_iterator iter = llsd_cats.beginArray(); - LLSD::array_const_iterator end = llsd_cats.endArray(); - for (; iter != end; ++iter) + LL_PROFILE_ZONE_NAMED("inventory load from file - categories"); + const LLSD& llsd_cats = inventory["categories"]; + if (llsd_cats.isArray()) { - LLPointer inv_cat = new LLViewerInventoryCategory(LLUUID::null); - if (inv_cat->importLLSDMap(*iter)) + LLSD::array_const_iterator iter = llsd_cats.beginArray(); + LLSD::array_const_iterator end = llsd_cats.endArray(); + for (; iter != end; ++iter) { - categories.push_back(inv_cat); + LLPointer inv_cat = new LLViewerInventoryCategory(LLUUID::null); + if (inv_cat->importLLSDMap(*iter)) + { + categories.push_back(inv_cat); + } } } } - const LLSD& llsd_items = inventory["items"]; - if (llsd_items.isArray()) { - LLSD::array_const_iterator iter = llsd_items.beginArray(); - LLSD::array_const_iterator end = llsd_items.endArray(); - for (; iter != end; ++iter) + LL_PROFILE_ZONE_NAMED("inventory load from file - items"); + const LLSD& llsd_items = inventory["items"]; + if (llsd_items.isArray()) { - LLPointer inv_item = new LLViewerInventoryItem; - if (inv_item->fromLLSD(*iter)) + LLSD::array_const_iterator iter = llsd_items.beginArray(); + LLSD::array_const_iterator end = llsd_items.endArray(); + for (; iter != end; ++iter) { - if (inv_item->getUUID().isNull()) - { - LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " - << inv_item->getName() << LL_ENDL; - } - else + LLPointer inv_item = new LLViewerInventoryItem; + if (inv_item->fromLLSD(*iter)) { - if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + if (inv_item->getUUID().isNull()) { - cats_to_update.insert(inv_item->getParentUUID()); + LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " << inv_item->getName() << LL_ENDL; } else { - items.push_back(inv_item); + if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + { + cats_to_update.insert(inv_item->getParentUUID()); + } + else + { + items.push_back(inv_item); + } } } - } - // TODO(brad) - figure out how to reenable this without breaking everything else - // static constexpr U64 BATCH_SIZE = 512U; - // if ((++lines_count % BATCH_SIZE) == 0) - // { - // // SL-19968 - make sure message system code gets a chance to run every so often - // pump_idle_startup_network(); - // } + // TODO(brad) - figure out how to reenable this without breaking everything else + // static constexpr U64 BATCH_SIZE = 512U; + // if ((++lines_count % BATCH_SIZE) == 0) + // { + // // SL-19968 - make sure message system code gets a chance to run every so often + // pump_idle_startup_network(); + // } + } } } } diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 2859923df90..05ada9121a3 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -201,13 +201,13 @@ class LLInventoryModel // the inventory using several different identifiers. // mInventory member data is the 'master' list of inventory, and // mCategoryMap and mItemMap store uuid->object mappings. - typedef std::map > cat_map_t; - typedef std::map > item_map_t; + typedef std::unordered_map > cat_map_t; + typedef std::unordered_map> item_map_t; cat_map_t mCategoryMap; item_map_t mItemMap; // This last set of indices is used to map parents to children. - typedef std::map parent_cat_map_t; - typedef std::map parent_item_map_t; + typedef std::unordered_map parent_cat_map_t; + typedef std::unordered_map parent_item_map_t; parent_cat_map_t mParentChildCategoryTree; parent_item_map_t mParentChildItemTree; @@ -329,6 +329,8 @@ class LLInventoryModel // user specified one or it does not exist, creates default category if it is missing. const LLUUID findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const; + const LLUUID getMarketplaceListingsUUID(); + // Get whatever special folder this object is a child of, if any. const LLViewerInventoryCategory *getFirstNondefaultParent(const LLUUID& obj_id) const; @@ -361,6 +363,8 @@ class LLInventoryModel private: mutable LLPointer mLastItem; // cache recent lookups + LLUUID mMarketplaceListingsUUID; + //-------------------------------------------------------------------- // Count //-------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 1e5f771ba78..82eefb50acf 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -828,7 +828,7 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis() // Intent is for marketplace request to happen after // main inventory is done, unless requested by floater mRecursiveMarketplaceFetchStarted = true; - const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID& marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); if (marketplacelistings_id.notNull()) { mFetchFolderQueue.emplace_front(marketplacelistings_id, FT_FOLDER_AND_CONTENT); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index cde87ede9b6..06dd8304163 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1849,6 +1849,7 @@ void LLInventoryPanel::purgeSelectedItems() { if (!mFolderRoot.get()) return; + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); const std::set inventory_selected = mFolderRoot.get()->getSelectionList(); if (inventory_selected.empty()) return; LLSD args; @@ -1858,12 +1859,17 @@ void LLInventoryPanel::purgeSelectedItems() it != end_it; ++it) { + // Selection allows items outside trash folder, only count the ones inside. LLUUID item_id = static_cast((*it)->getViewModelItem())->getUUID(); - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(item_id, cats, items, LLInventoryModel::INCLUDE_TRASH); - count += items.size() + cats.size(); - selected_items.push_back(item_id); + LLInventoryObject* obj = gInventory.getObject(item_id); + if (obj->getParentUUID() == trash_id) + { + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(item_id, cats, items, LLInventoryModel::INCLUDE_TRASH); + count += items.size() + cats.size(); + selected_items.push_back(item_id); + } } args["COUNT"] = static_cast(count); LLNotificationsUtil::add("PurgeSelectedItems", args, LLSD(), boost::bind(callbackPurgeSelectedItems, _1, _2, selected_items)); @@ -2119,8 +2125,7 @@ LLFolderViewItem* LLInventoryPanel::getItemByID(const LLUUID& id) { LL_PROFILE_ZONE_SCOPED; - std::map::iterator map_it; - map_it = mItemMap.find(id); + auto map_it = mItemMap.find(id); if (map_it != mItemMap.end()) { return map_it->second; diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index dc2e304ab35..ca2d5814bc6 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -300,7 +300,7 @@ class LLInventoryPanel : public LLPanel LLPointer mGroupedItemBridge; Params mParams; // stored copy of parameter block - std::map mItemMap; + std::unordered_map mItemMap; /** * Pointer to LLInventoryFolderViewModelBuilder. * diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 6e56aac270a..1329b1308dc 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -596,7 +596,7 @@ void LLLocalBitmap::updateUserVolumes(LLUUID old_id, LLUUID new_id, U32 channel) if (object->isSculpted() && object->getVolume() && object->getVolume()->getParams().getSculptID() == old_id) { - LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams* old_params = object->getSculptParams(); LLSculptParams new_params(*old_params); new_params.setSculptTexture(new_id, (*old_params).getSculptType()); object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, true); diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp index 51c38aba3ac..0a90cf0699e 100644 --- a/indra/newview/llmachineid.cpp +++ b/indra/newview/llmachineid.cpp @@ -398,6 +398,8 @@ bool getSerialNumber(unsigned char *unique_id, size_t len) S32 LLMachineID::init() { + LL_PROFILE_ZONE_SCOPED; + size_t len = sizeof(static_unique_id); memset(static_unique_id, 0, len); S32 ret_code = 0; diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index ac2f52a2623..30f634f6d41 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -850,7 +850,7 @@ void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot // Get/Post/Put requests to the SLM Server using the SLM API void LLMarketplaceData::getSLMListings() { - const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID marketplaceFolderId = gInventory.getMarketplaceListingsUUID(); setUpdating(marketplaceFolderId, true); LLCoros::instance().launch("getSLMListings", @@ -1757,7 +1757,7 @@ bool LLMarketplaceData::isUpdating(const LLUUID& folder_id, S32 depth) } else { - const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID marketplace_listings_uuid = gInventory.getMarketplaceListingsUUID(); std::set::iterator it = mPendingUpdateSet.find(marketplace_listings_uuid); if (it != mPendingUpdateSet.end()) { diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h index 1279b77ad4e..c04f8749234 100644 --- a/indra/newview/llmaterialmgr.h +++ b/indra/newview/llmaterialmgr.h @@ -33,9 +33,42 @@ #include "httprequest.h" #include "httpheaders.h" #include "httpoptions.h" +#include class LLViewerRegion; +// struct for TE-specific material ID query +class TEMaterialPair +{ +public: + U32 te; + LLMaterialID materialID; + + bool operator==(const TEMaterialPair& b) const { return (materialID == b.materialID) && (te == b.te); } +}; + +inline bool operator<(const TEMaterialPair& lhs, const TEMaterialPair& rhs) +{ + return (lhs.te < rhs.te) ? true : (lhs.materialID < rhs.materialID); +} + +// std::hash implementation for TEMaterialPair +namespace std +{ + template<> + struct hash + { + inline size_t operator()(const TEMaterialPair& p) const noexcept + { + // Utilize boost::hash_combine to generate a good hash + size_t seed = 0; + boost::hash_combine(seed, p.te + 1); + boost::hash_combine(seed, p.materialID); + return seed; + } + }; +} // namespace std + class LLMaterialMgr : public LLSingleton { LLSINGLETON(LLMaterialMgr); @@ -83,29 +116,6 @@ class LLMaterialMgr : public LLSingleton void onRegionRemoved(LLViewerRegion* regionp); private: - // struct for TE-specific material ID query - class TEMaterialPair - { - public: - - U32 te; - LLMaterialID materialID; - - bool operator==(const TEMaterialPair& b) const { return (materialID == b.materialID) && (te == b.te); } - }; - - // definitions follow class - friend std::hash; - friend size_t hash_value(const TEMaterialPair&) noexcept; - - friend inline bool operator<( - const LLMaterialMgr::TEMaterialPair& lhs, - const LLMaterialMgr::TEMaterialPair& rhs) - { - return (lhs.te < rhs.te) ? true : - (lhs.materialID < rhs.materialID); - } - typedef std::set material_queue_t; typedef std::map get_queue_t; typedef std::pair pending_material_t; @@ -113,7 +123,7 @@ class LLMaterialMgr : public LLSingleton typedef std::map get_callback_map_t; - typedef boost::unordered_map get_callback_te_map_t; + typedef std::unordered_map get_callback_te_map_t; typedef std::set getall_queue_t; typedef std::map getall_pending_map_t; typedef std::map getall_callback_map_t; @@ -142,23 +152,5 @@ class LLMaterialMgr : public LLSingleton U32 getMaxEntries(const LLViewerRegion* regionp); }; -// std::hash implementation for TEMaterialPair -namespace std -{ - template<> struct hash - { - inline size_t operator()(const LLMaterialMgr::TEMaterialPair& p) const noexcept - { - return size_t((p.te + 1) * p.materialID.getDigest64()); - } - }; -} - -// For use with boost containers. -inline size_t hash_value(const LLMaterialMgr::TEMaterialPair& p) noexcept -{ - return size_t((p.te + 1) * p.materialID.getDigest64()); -} - #endif // LL_LLMATERIALMGR_H diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index c0b1a5326ad..fb6ecedcbfd 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2847,8 +2847,44 @@ void LLMeshUploadThread::packModelIntance( texture_index.find(texture) == texture_index.end()) { texture_index[texture] = texture_num; - std::string str = texture_str.str(); - res["texture_list"][texture_num] = LLSD::Binary(str.begin(), str.end()); + if (include_textures) + { + std::string str = texture_str.str(); + res["texture_list"][texture_num] = LLSD::Binary(str.begin(), str.end()); + } + else + { // When not including the whole texture, we need to send some metadata about the image + // to ensure accurate price estimation. If not included, the server will assume all + // textures are 1024 x 1024, which could lead to a low estimate. + LLSD info = LLSD::emptyMap(); + + S32 texture_width = 0; + S32 texture_height = 0; + if (texture->hasSavedRawImage()) + { + LLImageDataLock lock(texture->getSavedRawImage()); + + LLPointer upload_file = LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage()); + + if (!upload_file.isNull() && upload_file->getDataSize() && !upload_file->isBufferInvalid()) + { + texture_width = upload_file->getWidth(); + texture_height = upload_file->getHeight(); + } + } + + if ((texture_width <= 0) || (texture_height <= 0)) + { + // Fall back to the texture's stored dimensions if we can't get dimensions from the raw image. + texture_width = texture->getFullWidth(); + texture_height = texture->getFullHeight(); + } + + info["width"] = texture_width; + info["height"] = texture_height; + res["texture_info"][texture_num] = info; + res["texture_list"][texture_num] = LLSD::Binary(); // empty binary to indicate texture is not included, for older server compatibility + } // store indexes for error handling; texture_list_dest.push_back(material.mDiffuseMapFilename); texture_num++; @@ -2881,8 +2917,8 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, std::vector& LLSD res; if (mDestinationFolderId.isNull()) { - result["folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT); - result["texture_folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE); + result["folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT); + result["texture_folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE); } else { @@ -3331,6 +3367,8 @@ void LLMeshRepoThread::notifyLoadedMeshes() loaded_queue.swap(mLoadedQ); mLoadedMutex->unlock(); + LL_PROFILE_ZONE_NAMED("notify loaded meshes"); + update_metrics = true; // Process the elements free of the lock @@ -3362,6 +3400,8 @@ void LLMeshRepoThread::notifyLoadedMeshes() unavil_queue.swap(mUnavailableQ); mLoadedMutex->unlock(); + LL_PROFILE_ZONE_NAMED("notify unavail meshes"); + update_metrics = true; // Process the elements free of the lock @@ -3380,6 +3420,7 @@ void LLMeshRepoThread::notifyLoadedMeshes() { if (mLoadedMutex->trylock()) { + LL_PROFILE_ZONE_NAMED("notify misc meshes"); std::deque> skin_info_q; std::deque skin_info_unavail_q; std::list decomp_q; @@ -4271,20 +4312,63 @@ S32 LLMeshRepository::update() return static_cast(size); } -void LLMeshRepository::unregisterMesh(LLVOVolume* vobj) +void LLMeshRepository::unregisterMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail) { - for (auto& lod : mLoadingMeshes) + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + + llassert((mesh_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH); + llassert(mesh_params.getSculptID().notNull()); + auto& lod = mLoadingMeshes[detail]; + auto param_iter = lod.find(mesh_params.getSculptID()); + if (param_iter != lod.end()) + { + param_iter->second.mVolumes.erase(vobj); + llassert(!param_iter->second.mVolumes.contains(vobj)); + if (param_iter->second.mVolumes.empty()) + { + lod.erase(param_iter); + } + } +} + +void LLMeshRepository::unregisterSkinInfo(const LLUUID& mesh_id, LLVOVolume* vobj) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + + llassert(mesh_id.notNull()); + auto skin_pair_iter = mLoadingSkins.find(mesh_id); + if (skin_pair_iter != mLoadingSkins.end()) { - for (auto& param : lod) + skin_pair_iter->second.mVolumes.erase(vobj); + llassert(!skin_pair_iter->second.mVolumes.contains(vobj)); + if (skin_pair_iter->second.mVolumes.empty()) { - vector_replace_with_last(param.second.mVolumes, vobj); + mLoadingSkins.erase(skin_pair_iter); } } +} - for (auto& skin_pair : mLoadingSkins) +// Lots of dead objects make expensive calls to +// LLMeshRepository::unregisterMesh which may delay shutdown. Avoid this by +// preemptively unregistering all meshes. +// We can also do this safely if all objects are confirmed dead for some other +// reason. +void LLMeshRepository::unregisterAllMeshes() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + + // The size of mLoadingMeshes and mLoadingSkins may be large and thus + // expensive to iterate over in LLVOVolume::~LLVOVolume. + // This is unnecessary during shutdown, so we ignore the referenced objects in the + // least expensive way which is still safe: by clearing these containers. + // Clear now and not in LLMeshRepository::shutdown because + // LLMeshRepository::notifyLoadedMeshes could (depending on invocation + // order) reference a pointer to an object after it has been deleted. + for (auto& lod : mLoadingMeshes) { - vector_replace_with_last(skin_pair.second.mVolumes, vobj); + lod.clear(); } + mLoadingSkins.clear(); } S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 new_lod, S32 last_lod) @@ -4306,7 +4390,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para mesh_load_map::iterator iter = mLoadingMeshes[new_lod].find(mesh_id); if (iter != mLoadingMeshes[new_lod].end()) { //request pending for this mesh, append volume id to list - auto it = std::find(iter->second.mVolumes.begin(), iter->second.mVolumes.end(), vobj); + auto it = iter->second.mVolumes.find(vobj); if (it == iter->second.mVolumes.end()) { iter->second.addVolume(vobj); } @@ -4804,7 +4888,7 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, LLVOV skin_load_map::iterator iter = mLoadingSkins.find(mesh_id); if (iter != mLoadingSkins.end()) { //request pending for this mesh, append volume id to list - auto it = std::find(iter->second.mVolumes.begin(), iter->second.mVolumes.end(), requesting_obj); + auto it = iter->second.mVolumes.find(requesting_obj); if (it == iter->second.mVolumes.end()) { iter->second.addVolume(requesting_obj); } diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 01b51e753e2..061b4b54286 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -290,7 +290,7 @@ class PendingRequestUUID : public PendingRequestBase class MeshLoadData { public: - MeshLoadData() {} + MeshLoadData() = default; ~MeshLoadData() { if (std::shared_ptr request = mRequest.lock()) @@ -300,19 +300,19 @@ class MeshLoadData } void initData(LLVOVolume* vol, std::shared_ptr& request) { - mVolumes.push_back(vol); + mVolumes.insert(vol); request->trackData(this); mRequest = request; } void addVolume(LLVOVolume* vol) { - mVolumes.push_back(vol); + mVolumes.insert(vol); if (std::shared_ptr request = mRequest.lock()) { request->setScoreDirty(); } } - std::vector mVolumes; + std::unordered_set mVolumes; private: std::weak_ptr mRequest; }; @@ -442,7 +442,7 @@ class LLMeshRepoThread : public LLThread LLCondition* mSignal; //map of known mesh headers - typedef boost::unordered_map mesh_header_map; // pair is header_size and data + typedef std::unordered_map mesh_header_map; // pair is header_size and data mesh_header_map mMeshHeader; class HeaderRequest : public RequestStats @@ -862,10 +862,12 @@ class LLMeshRepository LLMeshRepository(); void init(); + void unregisterAllMeshes(); void shutdown(); S32 update(); - void unregisterMesh(LLVOVolume* volume); + void unregisterMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail); + void unregisterSkinInfo(const LLUUID& mesh_id, LLVOVolume* vobj); //mesh management functions S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 new_lod = 0, S32 last_lod = -1); diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 6b1fbdce4c3..b2e21bea1ca 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -3461,7 +3461,7 @@ bool LLModelPreview::render() LLViewerCamera::getInstance()->setAspect(aspect); - LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); + LLViewerCamera::getInstance()->setViewNoBroadcast(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); LLVector3 offset = mCameraOffset; LLVector3 target_pos = mPreviewTarget + offset; diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index f47a8cd241b..b7bba02b9d8 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -582,6 +582,8 @@ std::vector LLMuteList::getMutes() const //----------------------------------------------------------------------------- bool LLMuteList::loadFromFile(const std::string& filename) { + LL_PROFILE_ZONE_SCOPED; + if(!filename.size()) { LL_WARNS() << "Mute List Filename is Empty!" << LL_ENDL; @@ -966,6 +968,8 @@ bool LLRenderMuteList::saveToFile() bool LLRenderMuteList::loadFromFile() { + LL_PROFILE_ZONE_SCOPED; + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "render_mute_settings.txt"); LLFILE* fp = LLFile::fopen(filename, "rb"); if (!fp) diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index dfead5ee8a8..9a0612e9f93 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -712,7 +712,14 @@ void LLNavigationBar::resizeLayoutPanel() } void LLNavigationBar::invokeSearch(std::string search_text) { - LLFloaterReg::showInstance("search", LLSD().with("category", "standard").with("query", LLSD(search_text))); + LLSD key; + key["category"] = "standard"; + key["query"] = search_text; + LLSD collections = LLSD::emptyArray(); + collections.append("destinations"); + collections.append("places"); + key["collections"] = collections; + LLFloaterReg::showInstance("search", key); } void LLNavigationBar::clearHistoryCache() diff --git a/indra/newview/llnearbyvoicemoderation.cpp b/indra/newview/llnearbyvoicemoderation.cpp new file mode 100644 index 00000000000..a5ee0e9423a --- /dev/null +++ b/indra/newview/llnearbyvoicemoderation.cpp @@ -0,0 +1,220 @@ +/** + * @file llnearbyvoicemoderation.cpp + * + * $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$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llnotificationsutil.h" +#include "llviewerregion.h" +#include "llvoavatar.h" +#include "llvoicechannel.h" +#include "llvoiceclient.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" +#include "roles_constants.h" + +#include "llnearbyvoicemoderation.h" + +LLNearbyVoiceModeration::LLNearbyVoiceModeration() +{ +} + +LLNearbyVoiceModeration::~LLNearbyVoiceModeration() +{ +} + +LLVOAvatar* LLNearbyVoiceModeration::getVOAvatarFromId(const LLUUID& agent_id) +{ + LLViewerObject *obj = gObjectList.findObject(agent_id); + while (obj && obj->isAttachment()) + { + obj = (LLViewerObject*)obj->getParent(); + } + + if (obj && obj->isAvatar()) + { + return (LLVOAvatar*)obj; + } + else + { + return NULL; + } +} + +const std::string LLNearbyVoiceModeration::getCapUrlFromRegion(LLViewerRegion* region) +{ + if (! region || ! region->capabilitiesReceived()) + { + return std::string(); + } + + std::string url = region->getCapability("SpatialVoiceModerationRequest"); + if (url.empty()) + { + LL_INFOS() << "Capability URL for region " << region->getName() << " is empty" << LL_ENDL; + return std::string(); + } + LL_INFOS() << "Capability URL for region " << region->getName() << " is " << url << LL_ENDL; + + return url; +} + +void LLNearbyVoiceModeration::requestMuteIndividual(const LLUUID& agent_id, bool mute) +{ + LLVOAvatar* avatar = getVOAvatarFromId(agent_id); + if (avatar) + { + const std::string cap_url = getCapUrlFromRegion(avatar->getRegion()); + if (cap_url.length()) + { + const std::string operand = mute ? "mute" : "unmute"; + + LLSD body; + body["operand"] = operand; + body["agent_id"] = agent_id; + + const std::string agent_name = avatar->getFullname(); + LL_INFOS() << "Resident " << agent_name + << " (" << agent_id << ")" << " applying " << operand << LL_ENDL; + + std::string success_msg = + STRINGIZE("Resident " << agent_name + << " (" << agent_id << ")" << " nearby voice was set to " << operand); + + std::string failure_msg = + STRINGIZE("Unable to change voice muting for resident " + << agent_name << " (" << agent_id << ")"); + + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost( + cap_url, + body, + success_msg, + failure_msg); + } + } +} + +void LLNearbyVoiceModeration::requestMuteAll(bool mute) +{ + // Use our own avatar to get the region name + LLViewerRegion* region = gAgent.getRegion(); + + const std::string cap_url = getCapUrlFromRegion(region); + if (cap_url.length()) + { + const std::string operand = mute ? "mute_all" : "unmute_all"; + + LLSD body; + body["operand"] = operand; + + LL_INFOS() << "For all residents in this region, applying: " << operand << LL_ENDL; + + std::string success_msg = + STRINGIZE("Nearby voice for all residents was set to: " << operand); + + std::string failure_msg = + STRINGIZE("Unable to set nearby voice for all residents to: " << operand); + + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost( + cap_url, + body, + success_msg, + failure_msg); + } +} + +void LLNearbyVoiceModeration::setMutedInfo(const std::string& channelID, bool mute) +{ + auto it = mChannelMuteMap.find(channelID); + if (it == mChannelMuteMap.end()) + { + if (mute) + { + // Channel is new and being muted + showMutedNotification(true); + } + mChannelMuteMap[channelID] = mute; + } + else + { + if (it->second != mute) + { + // Flag changed + showMutedNotification(mute); + it->second = mute; + } + } + if (mute && LLVoiceClient::getInstance()->getUserPTTState()) + { + LLVoiceClient::getInstance()->setUserPTTState(false); + } +} + +bool LLNearbyVoiceModeration::showNotificationIfNeeded() +{ + if (LLVoiceClient::getInstance()->inProximalChannel() && + LLVoiceClient::getInstance()->getIsModeratorMuted(gAgentID)) + { + return showMutedNotification(true); + } + return false; +} + +bool LLNearbyVoiceModeration::showMutedNotification(bool is_muted) +{ + // Check if the current voice channel is nearby chat + if (LLVoiceClient::getInstance()->inProximalChannel()) + { + LLNotificationsUtil::add(is_muted ? "NearbyVoiceMutedByModerator" : "NearbyVoiceUnmutedByModerator"); + return true; + } + return false; +} + +bool LLNearbyVoiceModeration::isNearbyChatModerator() +{ + // Region doesn't support WebRTC voice + if (!gAgent.getRegion() || !gAgent.getRegion()->isRegionWebRTCEnabled()) + { + return false; + } + + // Only show moderator options when connected to spatial voice chat + LLVoiceChannel* channel = LLVoiceChannel::getCurrentVoiceChannel(); + if (!channel || channel->getSessionID().notNull() || !LLAgent::isActionAllowed("speak")) + { + return false; + } + + if (LLViewerParcelMgr::getInstance()->isVoiceRestricted()) + { + // Only the parcel owner should have access to moderate parcel voice space + return LLViewerParcelMgr::getInstance()->allowVoiceModeration(); + } + else + { + return gAgent.canManageEstate(); + } +} diff --git a/indra/newview/llnearbyvoicemoderation.h b/indra/newview/llnearbyvoicemoderation.h new file mode 100644 index 00000000000..619f1698839 --- /dev/null +++ b/indra/newview/llnearbyvoicemoderation.h @@ -0,0 +1,50 @@ +/** + * @file llnearbyvoicemoderation.h + * + * $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$ + */ + +#pragma once + +class LLVOAvatar; + +class LLNearbyVoiceModeration : public LLSingleton { + LLSINGLETON(LLNearbyVoiceModeration); + ~LLNearbyVoiceModeration(); + + public: + void requestMuteIndividual(const LLUUID& userID, bool mute); + void requestMuteAll(bool mute); + + void setMutedInfo(const std::string& channelID, bool mute); + bool showMutedNotification(bool is_muted); + bool showNotificationIfNeeded(); + + bool isNearbyChatModerator(); + + private: + LLVOAvatar* getVOAvatarFromId(const LLUUID& id); + const std::string getCapUrlFromRegion(LLViewerRegion* region); + + boost::signals2::connection mParcelCallbackConnection; + std::map mChannelMuteMap; +}; diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index af472c4259d..63ec43458b0 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -47,6 +47,7 @@ #include "llagent.h" #include "llagentcamera.h" #include "llappviewer.h" // for gDisconnected +#include "llavataractions.h" #include "llcallingcard.h" // LLAvatarTracker #include "llfloaterland.h" #include "llfloaterworldmap.h" @@ -397,20 +398,41 @@ void LLNetMap::draw() LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgentCamera.getCameraPositionGlobal()); - // Draw avatars + std::vector> indexed_avatars; + indexed_avatars.reserve(avatar_ids.size()); for (U32 i = 0; i < avatar_ids.size(); i++) { - LLUUID uuid = avatar_ids[i]; + indexed_avatars.emplace_back(i, LLAvatarActions::isFriend(avatar_ids[i])); + } + + // Sort avatars so non-friends are drawn first and friend dots will appear on top + std::sort(indexed_avatars.begin(), indexed_avatars.end(), + [](const auto& a, const auto& b) { return a.second < b.second; }); + + uuid_vec_t sorted_avatar_ids; + std::vector sorted_positions; + sorted_avatar_ids.reserve(avatar_ids.size()); + sorted_positions.reserve(positions.size()); + + // Reorder avatar_ids and positions based on sorted indices + for (const auto& indexed_avatar : indexed_avatars) + { + sorted_avatar_ids.push_back(avatar_ids[indexed_avatar.first]); + sorted_positions.push_back(positions[indexed_avatar.first]); + } + + // Draw avatars + for (U32 i = 0; i < sorted_avatar_ids.size(); i++) + { + LLUUID uuid = sorted_avatar_ids[i]; // Skip self, we'll draw it later if (uuid == gAgent.getID()) continue; - pos_map = globalPosToView(positions[i]); - - bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL); + pos_map = globalPosToView(sorted_positions[i]); - LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color; + LLColor4 color = LLAvatarActions::isFriend(uuid) ? map_avatar_friend_color : map_avatar_color; - unknown_relative_z = positions[i].mdV[VZ] >= COARSEUPDATE_MAX_Z && + unknown_relative_z = sorted_positions[i].mdV[VZ] >= COARSEUPDATE_MAX_Z && camera_position.mV[VZ] >= COARSEUPDATE_MAX_Z; LLWorldMapView::drawAvatar( diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 8589afae06f..852f2dab219 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -850,7 +850,12 @@ void LLOutfitGallery::updateAddedCategory(LLUUID cat_id) // Start observing changes in "My Outfits" category. mCategoriesObserver->addCategory(cat_id, - boost::bind(&LLOutfitGallery::refreshOutfit, this, cat_id), true); + [this, cat_id]() + { + mPendingOutfitRefreshes.insert(cat_id); + startIdleLoop(cat_id); + }, + true); outfit_category->fetch(); refreshOutfit(cat_id); @@ -901,6 +906,18 @@ void LLOutfitGallery::updateChangedCategoryName(LLViewerInventoryCategory *cat, } } +bool LLOutfitGallery::updateOneOutfit() +{ + if (mPendingOutfitRefreshes.empty()) + return false; + + auto it = mPendingOutfitRefreshes.begin(); + LLUUID outfit_id = *it; + mPendingOutfitRefreshes.erase(it); + refreshOutfit(outfit_id); + return true; +} + void LLOutfitGallery::onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id) { if (mOutfitMenu && cat_id.notNull()) diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h index 5801a32a39f..183b6ea9d55 100644 --- a/indra/newview/lloutfitgallery.h +++ b/indra/newview/lloutfitgallery.h @@ -98,6 +98,7 @@ class LLOutfitGallery : public LLOutfitListBase /*virtual*/ void updateAddedCategory(LLUUID cat_id); /*virtual*/ void updateRemovedCategory(LLUUID cat_id); /*virtual*/ void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name); + /*virtual*/ bool updateOneOutfit(); // bulk processing, scheduled by observer when updates are needed /*virtual*/ bool hasItemSelected(); /*virtual*/ bool canWearSelected(); @@ -190,6 +191,7 @@ class LLOutfitGallery : public LLOutfitListBase typedef item_num_map_t::value_type item_numb_map_value_t; item_num_map_t mItemIndexMap; std::map mIndexToItemMap; + std::set mPendingOutfitRefreshes; LLInventoryCategoriesObserver* mOutfitsObserver; diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 32831fcd9bf..7db79c70106 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -1055,6 +1055,15 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) } } +void LLOutfitListBase::startIdleLoop(const LLUUID cat_id) +{ + if (mRefreshListState.CategoryUUID.isNull()) + { + mRefreshListState.CategoryUUID = cat_id; + gIdleCallbacks.addFunction(onIdle, this); + } +} + // static void LLOutfitListBase::onIdle(void* userdata) { @@ -1129,6 +1138,14 @@ void LLOutfitListBase::onIdleRefreshList() return; } + // Let derived classes process their own updates. + while (updateOneOutfit()) + { + curent_time = LLTimer::getTotalSeconds(); + if (curent_time >= end_time) + return; + } + sortOutfits(); highlightBaseOutfit(); diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index bcf7e45696a..408ff07116c 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -95,6 +95,17 @@ class LLOutfitListBase : public LLPanelAppearanceTab virtual void updateAddedCategory(LLUUID cat_id) = 0; virtual void updateRemovedCategory(LLUUID cat_id) = 0; virtual void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name) = 0; + + /* + * Optional hook for derived classes to perform additional processing. + * This is called by the outfit list update logic after the core + * bookkeeping for an outfit has been handled. + * + * @return true if update processing should continue, + * false if no additional work is required. + * The base implementation returns false. + */ + virtual bool updateOneOutfit() { return false; }; virtual void sortOutfits(); void removeSelected(); @@ -138,6 +149,7 @@ class LLOutfitListBase : public LLPanelAppearanceTab bool isOutfitFolder(LLViewerInventoryCategory* cat) const; + void startIdleLoop(const LLUUID cat_id); static void onIdle(void* userdata); void onIdleRefreshList(); @@ -150,6 +162,7 @@ class LLOutfitListBase : public LLPanelAppearanceTab uuid_vec_t::const_iterator RemovedIterator; } mRefreshListState; std::set mChangedItems; + std::set mPendingOutfitRefreshes; bool mIsInitialized; LLInventoryCategoriesObserver* mCategoriesObserver; diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index bcb51b22ca2..128ba42efd4 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -852,6 +852,27 @@ struct LLPanelFaceSetAlignedTEFunctor : public LLSelectedTEFunctor LLPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, uv_scale.mV[VX], te, object->getID()); LLPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, uv_scale.mV[VY], te, object->getID()); } + + // Also align GLTF material if any + S32 gltf_info_index = 0; // base texture + LLVector2 gltf_offset, gltf_scale; + F32 gltf_rot; + if (facep->calcAlignedPlanarGLTF(mCenterFace, &gltf_offset, &gltf_scale, &gltf_rot, gltf_info_index)) + { + LLGLTFMaterial new_override; + const LLTextureEntry* tep = object->getTE(te); + if (tep && tep->getGLTFMaterialOverride()) + { + new_override = *tep->getGLTFMaterialOverride(); + } + + LLGLTFMaterial::TextureTransform& transform = new_override.mTextureTransform[gltf_info_index]; + transform.mOffset.set(gltf_offset.mV[0], gltf_offset.mV[1]); + transform.mScale.set(gltf_scale.mV[0], gltf_scale.mV[1]); + transform.mRotation = gltf_rot; + + LLGLTFMaterialList::queueModify(object, te, &new_override); + } } if (!set_aligned) { diff --git a/indra/newview/llpanelgenerictip.cpp b/indra/newview/llpanelgenerictip.cpp index bc2b28269f4..1b5228713ec 100644 --- a/indra/newview/llpanelgenerictip.cpp +++ b/indra/newview/llpanelgenerictip.cpp @@ -43,5 +43,13 @@ LLPanelGenericTip::LLPanelGenericTip( S32 max_line_count = gSavedSettings.getS32("TipToastMessageLineCount"); snapToMessageHeight(getChild ("message"), max_line_count); + + // Check if notification should respond to mouse clicks + if (notification->getPayload().has("respond_on_mousedown") + && notification->getPayload()["respond_on_mousedown"]) + { + setMouseDownCallback(boost::bind(&LLNotification::respond, + notification, notification->getResponseTemplate())); + } } diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index ecb66f9cea4..ad65293b984 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -191,6 +191,13 @@ bool LLPanelGroup::postBuild() mButtonJoin->setCommitCallback(boost::bind(&LLPanelGroup::onBtnJoin,this)); mJoinText = panel_general->getChild("join_cost_text"); + + mButtonActivate = panel_general->getChild("btn_activate"); + mButtonActivate->setVisible(false); + mButtonActivate->setEnabled(gAgent.getGroupID() != mID); + mButtonActivate->setCommitCallback(boost::bind(&LLPanelGroup::onBtnActivate, this)); + + gAgent.addListener(this, "new group"); } LLVoiceClient::addObserver(this); @@ -267,6 +274,7 @@ void LLPanelGroup::onBtnJoin() if (LLGroupActions::isInGroup(mID)) { LLGroupActions::leave(mID); + mButtonActivate->setVisible(false); } else { @@ -275,6 +283,12 @@ void LLPanelGroup::onBtnJoin() } } +void LLPanelGroup::onBtnActivate() +{ + LLGroupActions::activate(mID); + mButtonActivate->setEnabled(false); +} + void LLPanelGroup::changed(LLGroupChange gc) { for(std::vector::iterator it = mTabs.begin();it!=mTabs.end();++it) @@ -312,6 +326,8 @@ void LLPanelGroup::update(LLGroupChange gc) bool join_btn_visible = is_member || gdatap->mOpenEnrollment; mButtonJoin->setVisible(join_btn_visible); + mButtonActivate->setEnabled(gAgent.getGroupID() != mID); + mButtonActivate->setVisible(is_member); mJoinText->setVisible(join_btn_visible); if (is_member) @@ -384,6 +400,8 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id) if(mButtonJoin) mButtonJoin->setVisible(false); + if (mButtonActivate) + mButtonActivate->setVisible(false); if(is_null_group_id)//creating new group @@ -598,4 +616,20 @@ void LLPanelGroup::showNotice(const std::string& subject, } +bool LLPanelGroup::handleEvent(LLPointer event, const LLSD& userdata) +{ + if (event->desc() == "new group") + { + mButtonActivate->setEnabled(gAgent.getGroupID() != mID); + return true; + } + + if (event->desc() == "value_changed") + { + mButtonActivate->setEnabled(gAgent.getGroupID() != mID); + return true; + } + + return false; +} diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h index b43a93bc400..d3550264a0e 100644 --- a/indra/newview/llpanelgroup.h +++ b/indra/newview/llpanelgroup.h @@ -26,6 +26,7 @@ #ifndef LL_LLPANELGROUP_H #define LL_LLPANELGROUP_H +#include "llevent.h" #include "llgroupmgr.h" #include "llpanel.h" #include "lltimer.h" @@ -44,7 +45,8 @@ class LLAgent; class LLPanelGroup : public LLPanel, public LLGroupMgrObserver, - public LLVoiceClientStatusObserver + public LLVoiceClientStatusObserver, + public LLOldEvents::LLSimpleListener { public: LLPanelGroup(); @@ -94,6 +96,7 @@ class LLPanelGroup : public LLPanel, void onBackBtnClick(); void onBtnJoin(); + void onBtnActivate(); static void onBtnApply(void*); static void onBtnRefresh(void*); @@ -120,11 +123,15 @@ class LLPanelGroup : public LLPanel, LLUICtrl* mGroupNameCtrl = nullptr; LLButton* mButtonJoin = nullptr; + LLButton* mButtonActivate = nullptr; LLButton* mButtonApply = nullptr; LLButton* mButtonCall = nullptr; LLButton* mButtonChat = nullptr; LLButton* mButtonRefresh = nullptr; LLUICtrl* mJoinText; + +private: + bool handleEvent(LLPointer event, const LLSD& userdata); // for agent group list changes }; class LLPanelGroupTab : public LLPanel diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index fe9145bf712..868e02f28b6 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -188,7 +188,8 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, mUsernameLength(0), mPasswordLength(0), mLocationLength(0), - mShowFavorites(false) + mShowFavorites(false), + mAlertNotif(false) { setBackgroundVisible(false); setBackgroundOpaque(true); @@ -219,6 +220,11 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, // STEAM-14: When user presses Enter with this field in focus, initiate login password_edit->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, false)); + childSetAction("connect_btn", onClickConnect, this); + + mLoginBtn = getChild("connect_btn"); + setDefaultBtn(mLoginBtn); + // change z sort of clickable text to be behind buttons sendChildToBack(getChildView("forgot_password_text")); sendChildToBack(getChildView("sign_up_text")); @@ -295,11 +301,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, onUpdateStartSLURL(start_slurl); // updates grid if needed } - childSetAction("connect_btn", onClickConnect, this); - - LLButton* def_btn = getChild("connect_btn"); - setDefaultBtn(def_btn); - std::string channel = LLVersionInfo::instance().getChannel(); std::string version = stringize(LLVersionInfo::instance().getShortVersion(), " (", LLVersionInfo::instance().getBuild(), ')'); @@ -327,6 +328,8 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLCheckBoxCtrl* remember_name = getChild("remember_name"); remember_name->setCommitCallback(boost::bind(&LLPanelLogin::onRememberUserCheck, this)); getChild("remember_password")->setCommitCallback(boost::bind(&LLPanelLogin::onRememberPasswordCheck, this)); + + mAlertListener = LLNotifications::instance().getChannel("Alerts")->connectChanged([this](const LLSD& notify){ return onUpdateNotification(notify); }); } void LLPanelLogin::addFavoritesToStartLocation() @@ -409,7 +412,7 @@ void LLPanelLogin::addFavoritesToStartLocation() gSavedSettings.setBOOL("RememberPassword", save_password); if (!save_password) { - getChild("connect_btn")->setEnabled(false); + mLoginBtn->setEnabled(false); } update_password_setting = false; } @@ -936,7 +939,7 @@ void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev // static void LLPanelLogin::onClickConnect(bool commit_fields) { - if (sInstance && sInstance->mCallback) + if (sInstance && sInstance->mCallback && !sInstance->mAlertNotif) { if (commit_fields) { @@ -1193,9 +1196,7 @@ void LLPanelLogin::updateServer() void LLPanelLogin::updateLoginButtons() { - LLButton* login_btn = getChild("connect_btn"); - - login_btn->setEnabled(mUsernameLength != 0 && mPasswordLength != 0); + mLoginBtn->setEnabled(mUsernameLength != 0 && mPasswordLength != 0 && !mAlertNotif); if (!mFirstLoginThisInstall) { @@ -1367,3 +1368,22 @@ std::string LLPanelLogin::getUserName(LLPointer &cred) return "unknown"; } +bool LLPanelLogin::onUpdateNotification(const LLSD& notify) +{ + // disable Login button while alert notification is displayed + LLNotificationPtr notifyp = LLNotifications::instance().find(notify["id"].asUUID()); + if (notifyp && notifyp->getName() == "PromptOptionalUpdate") + { + std::string sigtype = notify["sigtype"].asString(); + if (sigtype == "add") + { + mAlertNotif = true; + } + else if (sigtype == "delete") + { + mAlertNotif = false; + } + updateLoginButtons(); + } + return false; +} diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index a1bf25fb05b..f527aa53ac6 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -105,8 +105,11 @@ class LLPanelLogin: static void onRememberPasswordCheck(void*); static void onPassKey(LLLineEditor* caller, void* user_data); + bool onUpdateNotification(const LLSD& notify); + private: std::unique_ptr mListener; + LLTempBoundListener mAlertListener; void updateLoginButtons(); void populateUserList(LLPointer credential); @@ -126,6 +129,9 @@ class LLPanelLogin: unsigned int mUsernameLength; unsigned int mPasswordLength; unsigned int mLocationLength; + + bool mAlertNotif; + LLButton* mLoginBtn; }; #endif diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index ad7aa57842f..04eebcefc14 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -216,14 +216,14 @@ bool LLPanelMainInventory::postBuild() mWornItemsPanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mWornItemsPanel, _1, _2)); } - LLInventoryPanel* favorites_panel = getChild(FAVORITES); - if (favorites_panel) + mFavoritesPanel = getChild(FAVORITES); + if (mFavoritesPanel) { - favorites_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER)); - LLInventoryFilter& favorites_filter = favorites_panel->getFilter(); + mFavoritesPanel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER)); + LLInventoryFilter& favorites_filter = mFavoritesPanel->getFilter(); favorites_filter.setEmptyLookupMessage("InventoryNoMatchingFavorites"); favorites_filter.markDefault(); - favorites_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, favorites_panel, _1, _2)); + mFavoritesPanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mFavoritesPanel, _1, _2)); } mSearchTypeCombo = getChild("search_type"); @@ -319,6 +319,10 @@ bool LLPanelMainInventory::postBuild() menu->getChild("Upload Animation")->setLabelArg("[COST]", animation_upload_cost_str); } + mFilterTabs->setTabVisibility(mRecentPanel, gSavedSettings.getBOOL("InventoryShowRecentTab")); + mFilterTabs->setTabVisibility(mWornItemsPanel, gSavedSettings.getBOOL("InventoryShowWornTab")); + mFilterTabs->setTabVisibility(mFavoritesPanel, gSavedSettings.getBOOL("InventoryShowFavoritesTab")); + // Trigger callback for focus received so we can deselect items in inbox/outbox LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLPanelMainInventory::onFocusReceived, this)); @@ -1613,8 +1617,10 @@ void LLPanelMainInventory::initSingleFolderRoot(const LLUUID& start_folder_id) void LLPanelMainInventory::initInventoryViews() { mAllItemsPanel->initializeViewBuilding(); - mRecentPanel->initializeViewBuilding(); - mWornItemsPanel->initializeViewBuilding(); + if (gSavedSettings.getBOOL("InventoryShowRecentTab")) + mRecentPanel->initializeViewBuilding(); + if (gSavedSettings.getBOOL("InventoryShowWornTab")) + mWornItemsPanel->initializeViewBuilding(); } void LLPanelMainInventory::toggleViewMode() @@ -2056,6 +2062,27 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata) { setViewMode(MODE_COMBINATION); } + + if (command_name == "toggle_recent_tab") + { + bool visibility = !gSavedSettings.getBOOL("InventoryShowRecentTab"); + gSavedSettings.setBOOL("InventoryShowRecentTab", visibility); + mFilterTabs->setTabVisibility(mRecentPanel, visibility); + mRecentPanel->initializeViewBuilding(); + } + if (command_name == "toggle_worn_tab") + { + bool visibility = !gSavedSettings.getBOOL("InventoryShowWornTab"); + gSavedSettings.setBOOL("InventoryShowWornTab", visibility); + mFilterTabs->setTabVisibility(mWornItemsPanel, visibility); + mWornItemsPanel->initializeViewBuilding(); + } + if (command_name == "toggle_favorites_tab") + { + bool visibility = !gSavedSettings.getBOOL("InventoryShowFavoritesTab"); + gSavedSettings.setBOOL("InventoryShowFavoritesTab", visibility); + mFilterTabs->setTabVisibility(mFavoritesPanel, visibility); + } } void LLPanelMainInventory::onVisibilityChange( bool new_visibility ) @@ -2283,6 +2310,19 @@ bool LLPanelMainInventory::isActionChecked(const LLSD& userdata) return isCombinationViewMode(); } + if (command_name == "recent_tab") + { + return mFilterTabs->getTabVisibility(mRecentPanel); + } + if (command_name == "worn_tab") + { + return mFilterTabs->getTabVisibility(mWornItemsPanel); + } + if (command_name == "favorites_tab") + { + return mFilterTabs->getTabVisibility(mFavoritesPanel); + } + return false; } diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index a78c0c0fad0..03650e7fc19 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -199,6 +199,7 @@ class LLPanelMainInventory : public LLPanel, LLInventoryObserver LLInventoryPanel* mAllItemsPanel = nullptr; LLInventoryPanel* mRecentPanel = nullptr; LLInventoryPanel* mWornItemsPanel = nullptr; + LLInventoryPanel* mFavoritesPanel = nullptr; bool mResortActivePanel; LLSaveFolderState* mSavedFolderState; std::string mFilterText; diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 23e6a9fbcf5..69be65d9c95 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -625,7 +625,7 @@ void LLPanelObject::getState( ) } - if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) + if (objectp->getSculptParams()) { selected_item = MI_SCULPT; //LLFirstUse::useSculptedPrim(); @@ -1078,7 +1078,7 @@ void LLPanelObject::getState( ) LLUUID id; - LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams *sculpt_params = objectp->getSculptParams(); if (sculpt_params) // if we have a legal sculpt param block for this object: @@ -1246,13 +1246,13 @@ void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata ) if (selected_type == MI_SCULPT) { self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, true, true); - LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams *sculpt_params = self->mObject->getSculptParams(); if (sculpt_params) volume_params.setSculptID(sculpt_params->getSculptTexture(), sculpt_params->getSculptType()); } else { - LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams *sculpt_params = self->mObject->getSculptParams(); if (sculpt_params) self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, false, true); } @@ -2264,24 +2264,21 @@ void LLPanelObject::onCopyParams() mClipboardParams["volume_params"] = params.asLLSD(); // Sculpted Prim - if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) + LLSculptParams *sculpt_params = objectp->getSculptParams(); + if (sculpt_params) { - LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - if (sculpt_params) + LLUUID texture_id = sculpt_params->getSculptTexture(); + if (get_can_copy_texture(texture_id)) { - LLUUID texture_id = sculpt_params->getSculptTexture(); - if (get_can_copy_texture(texture_id)) - { - LL_DEBUGS("FloaterTools") << "Recording texture" << LL_ENDL; - mClipboardParams["sculpt"]["id"] = texture_id; - } - else - { - mClipboardParams["sculpt"]["id"] = SCULPT_DEFAULT_TEXTURE; - } - - mClipboardParams["sculpt"]["type"] = sculpt_params->getSculptType(); + LL_DEBUGS("FloaterTools") << "Recording texture" << LL_ENDL; + mClipboardParams["sculpt"]["id"] = texture_id; } + else + { + mClipboardParams["sculpt"]["id"] = SCULPT_DEFAULT_TEXTURE; + } + + mClipboardParams["sculpt"]["type"] = sculpt_params->getSculptType(); } } @@ -2304,7 +2301,7 @@ void LLPanelObject::onPasteParams() } else { - LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams *sculpt_params = objectp->getSculptParams(); if (sculpt_params) { objectp->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, false, true); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index a31a54bb670..d27ce81e4f0 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1830,7 +1830,7 @@ void LLPanelObjectInventory::onFocusReceived() LLFolderViewItem* LLPanelObjectInventory::getItemByID( const LLUUID& id ) { - std::map::iterator map_it = mItemMap.find(id); + auto map_it = mItemMap.find(id); if (map_it != mItemMap.end()) { return map_it->second; diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h index 154639e4bb5..13e27b489c6 100644 --- a/indra/newview/llpanelobjectinventory.h +++ b/indra/newview/llpanelobjectinventory.h @@ -109,7 +109,7 @@ class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener bool isSelectionRemovable(); private: - std::map mItemMap; + std::unordered_map mItemMap; LLScrollContainer* mScroller; LLFolderView* mFolders; diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index cbf5819fda6..cff09b07789 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -786,7 +786,9 @@ void LLPanelPermissions::refresh() getChildView("Edit Cost")->setEnabled(change_sale_allowed && !is_for_sale_mixed); // Set the checkbox to tentative if the prices of each object selected // are not the same. - getChild("checkbox for sale")->setTentative( is_for_sale_mixed); + // If object is marked for sale yet is not transferable, mark as tentative, + // as it is in a state where it can't be sold + getChild("checkbox for sale")->setTentative((!can_transfer && num_for_sale) || is_for_sale_mixed); getChildView("sale type")->setEnabled(num_for_sale && can_transfer && !is_sale_price_mixed); getChildView("Next owner can:")->setEnabled(true); diff --git a/indra/newview/llpanelvoiceeffect.cpp b/indra/newview/llpanelvoiceeffect.cpp deleted file mode 100644 index a0129b2cb1f..00000000000 --- a/indra/newview/llpanelvoiceeffect.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/** - * @file llpanelvoiceeffect.cpp - * @author Aimee - * @brief Panel to select Voice Morphs. - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llpanelvoiceeffect.h" - -#include "llcombobox.h" -#include "llfloaterreg.h" -#include "llpanel.h" -#include "lltrans.h" -#include "lltransientfloatermgr.h" -#include "llvoiceclient.h" -#include "llweb.h" - -static LLPanelInjector t_panel_voice_effect("panel_voice_effect"); - -LLPanelVoiceEffect::LLPanelVoiceEffect() - : mVoiceEffectCombo(NULL) -{ - mCommitCallbackRegistrar.add("Voice.CommitVoiceEffect", boost::bind(&LLPanelVoiceEffect::onCommitVoiceEffect, this)); -} - -LLPanelVoiceEffect::~LLPanelVoiceEffect() -{ - LLView* combo_list_view = mVoiceEffectCombo->getChildView("ComboBox"); - LLTransientFloaterMgr::getInstance()->removeControlView(combo_list_view); - - if(LLVoiceClient::instanceExists()) - { - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (effect_interface) - { - effect_interface->removeObserver(this); - } - } -} - -// virtual -bool LLPanelVoiceEffect::postBuild() -{ - mVoiceEffectCombo = getChild("voice_effect"); - - // Need to tell LLTransientFloaterMgr about the combo list, otherwise it can't - // be clicked while in a docked floater as it extends outside the floater area. - LLView* combo_list_view = mVoiceEffectCombo->getChildView("ComboBox"); - LLTransientFloaterMgr::getInstance()->addControlView(combo_list_view); - - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (effect_interface) - { - effect_interface->addObserver(this); - } - - update(true); - - return true; -} - -////////////////////////////////////////////////////////////////////////// -/// PRIVATE SECTION -////////////////////////////////////////////////////////////////////////// - -void LLPanelVoiceEffect::onCommitVoiceEffect() -{ - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (!effect_interface) - { - mVoiceEffectCombo->setEnabled(false); - return; - } - - LLSD value = mVoiceEffectCombo->getValue(); - if (value.asInteger() == PREVIEW_VOICE_EFFECTS) - { - // Open the Voice Morph preview floater - LLFloaterReg::showInstance("voice_effect"); - } - else if (value.asInteger() == GET_VOICE_EFFECTS) - { - // Open the voice morphing info web page - LLWeb::loadURL(LLTrans::getString("voice_morphing_url")); - } - else - { - effect_interface->setVoiceEffect(value.asUUID()); - } - - mVoiceEffectCombo->setValue(effect_interface->getVoiceEffect()); -} - -// virtual -void LLPanelVoiceEffect::onVoiceEffectChanged(bool effect_list_updated) -{ - update(effect_list_updated); -} - -void LLPanelVoiceEffect::update(bool list_updated) -{ - if (mVoiceEffectCombo) - { - LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); - if (!effect_interface) return; - if (list_updated) - { - // Add the default "No Voice Morph" entry. - mVoiceEffectCombo->removeall(); - mVoiceEffectCombo->add(getString("no_voice_effect"), LLUUID::null); - mVoiceEffectCombo->addSeparator(); - - // Add entries for each Voice Morph. - const voice_effect_list_t& effect_list = effect_interface->getVoiceEffectList(); - if (!effect_list.empty()) - { - for (voice_effect_list_t::const_iterator it = effect_list.begin(); it != effect_list.end(); ++it) - { - mVoiceEffectCombo->add(it->first, it->second, ADD_BOTTOM); - } - - mVoiceEffectCombo->addSeparator(); - } - - // Add the fixed entries to go to the preview floater or marketing page. - mVoiceEffectCombo->add(getString("preview_voice_effects"), PREVIEW_VOICE_EFFECTS); - mVoiceEffectCombo->add(getString("get_voice_effects"), GET_VOICE_EFFECTS); - } - - if (effect_interface && LLVoiceClient::instance().isVoiceWorking()) - { - // Select the current Voice Morph. - mVoiceEffectCombo->setValue(effect_interface->getVoiceEffect()); - mVoiceEffectCombo->setEnabled(true); - } - else - { - // If voice isn't working or Voice Effects are not supported disable the control. - mVoiceEffectCombo->setValue(LLUUID::null); - mVoiceEffectCombo->setEnabled(false); - } - } -} diff --git a/indra/newview/llpanelvoiceeffect.h b/indra/newview/llpanelvoiceeffect.h deleted file mode 100644 index f920e410815..00000000000 --- a/indra/newview/llpanelvoiceeffect.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file llpanelvoiceeffect.h - * @author Aimee - * @brief Panel to select Voice Effects. - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_PANELVOICEEFFECT_H -#define LL_PANELVOICEEFFECT_H - -#include "llpanel.h" -#include "llvoiceclient.h" - -class LLComboBox; - -class LLPanelVoiceEffect - : public LLPanel - , public LLVoiceEffectObserver -{ -public: - LOG_CLASS(LLPanelVoiceEffect); - - LLPanelVoiceEffect(); - virtual ~LLPanelVoiceEffect(); - - bool postBuild() override; - -private: - void onCommitVoiceEffect(); - void update(bool list_updated); - - /// Called by voice effect provider when voice effect list is changed. - void onVoiceEffectChanged(bool effect_list_updated) override; - - // Fixed entries in the Voice Morph list - typedef enum e_voice_effect_combo_items - { - NO_VOICE_EFFECT = 0, - PREVIEW_VOICE_EFFECTS = 1, - GET_VOICE_EFFECTS = 2 - } EVoiceEffectComboItems; - - LLComboBox* mVoiceEffectCombo; -}; - - -#endif //LL_PANELVOICEEFFECT_H diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 5916163f601..94864797d52 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -532,7 +532,7 @@ void LLPanelVolume::getState( ) getChildView("FlexForceY")->setEnabled(true); getChildView("FlexForceZ")->setEnabled(true); - LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + LLFlexibleObjectData *attributes = objectp->getFlexibleObjectData(); getChild("FlexNumSections")->setValue((F32)attributes->getSimulateLOD()); getChild("FlexGravity")->setValue(attributes->getGravity()); @@ -643,7 +643,7 @@ void LLPanelVolume::getState( ) mComboPhysicsShapeType->add(getString("None"), LLSD(1)); bool isMesh = false; - LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams *sculpt_params = objectp->getSculptParams(); if (sculpt_params) { U8 sculpt_type = sculpt_params->getSculptType(); @@ -1043,7 +1043,7 @@ void LLPanelVolume::onCopyFeatures() // Flexi Prim if (volobjp && volobjp->isFlexible()) { - LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + LLFlexibleObjectData *attributes = objectp->getFlexibleObjectData(); if (attributes) { clipboard["flex"]["lod"] = attributes->getSimulateLOD(); @@ -1141,7 +1141,7 @@ void LLPanelVolume::onPasteFeatures() objectp->setClickAction(CLICK_ACTION_NONE); } - LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + LLFlexibleObjectData *attributes = objectp->getFlexibleObjectData(); if (attributes) { LLFlexibleObjectData new_attributes; @@ -1568,7 +1568,7 @@ void LLPanelVolume::onCommitFlexible( LLUICtrl* ctrl, void* userdata ) return; } - LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + LLFlexibleObjectData *attributes = objectp->getFlexibleObjectData(); if (attributes) { LLFlexibleObjectData new_attributes; diff --git a/indra/newview/llperfstats.h b/indra/newview/llperfstats.h index 1a2098ec7e0..38deb872377 100644 --- a/indra/newview/llperfstats.h +++ b/indra/newview/llperfstats.h @@ -223,7 +223,7 @@ namespace LLPerfStats static void updateMeanFrameTime(U64 tot_frame_time_raw); // StatsArray is a uint64_t for each possible statistic type. using StatsArray = std::array(LLPerfStats::StatType_t::STATS_COUNT)>; - using StatsMap = std::unordered_map>; + using StatsMap = std::unordered_map; using StatsTypeMatrix = std::array(LLPerfStats::ObjType_t::OT_COUNT)>; using StatsSummaryArray = std::array(LLPerfStats::ObjType_t::OT_COUNT)>; diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 9a991727b24..eefd19e1537 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -79,6 +79,7 @@ LLPreviewNotecard::LLPreviewNotecard(const LLSD& key) //const LLUUID& item_id, LLPreviewNotecard::~LLPreviewNotecard() { delete mLiveFile; + mEditor = nullptr; } bool LLPreviewNotecard::postBuild() @@ -166,7 +167,7 @@ bool LLPreviewNotecard::handleKeyHere(KEY key, MASK mask) // virtual bool LLPreviewNotecard::canClose() { - if(mForceClose || mEditor->isPristine()) + if(mForceClose || !mEditor || mEditor->isPristine()) { return true; } diff --git a/indra/newview/llscriptruntimeperms.h b/indra/newview/llscriptruntimeperms.h index 300304c21bd..6350b61d082 100644 --- a/indra/newview/llscriptruntimeperms.h +++ b/indra/newview/llscriptruntimeperms.h @@ -24,10 +24,7 @@ * $/LicenseInfo$ */ -#ifndef LL_LLSCRIPTRUNTIME_PERMS_H -#define LL_LLSCRIPTRUNTIME_PERMS_H - -#include +#pragma once typedef struct _script_perm { std::string question; @@ -37,12 +34,12 @@ typedef struct _script_perm { question(q), permbit(b), caution(c) {} } script_perm_t; -const U32 NUM_SCRIPT_PERMISSIONS = 18; +const U32 NUM_SCRIPT_PERMISSIONS = 19; const S32 SCRIPT_PERMISSION_DEBIT = 0; const S32 SCRIPT_PERMISSION_TRIGGER_ANIMATION = 3; const S32 SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS = 14; -static const boost::array SCRIPT_PERMISSIONS = {{ +static const std::array SCRIPT_PERMISSIONS = {{ _script_perm("ScriptTakeMoney", (0x1 << 1), true), _script_perm("ActOnControlInputs", (0x1 << 2), false), _script_perm("RemapControlInputs", (0x1 << 3), false), @@ -60,7 +57,7 @@ static const boost::array SCRIPT_PERMISSI _script_perm("OverrideYourAnimations", (0x1 << 15), false), _script_perm("ScriptReturnObjects", (0x1 << 16), false), _script_perm("ForceSitAvatar", (0x1 << 17), false), - _script_perm("ChangeEnvSettings", (0x1 << 18), false) + _script_perm("ChangeEnvSettings", (0x1 << 18), false), + _script_perm("PrivilegedLandAccess",(0x1 << 19), true) } }; -#endif // LL_LLSCRIPTRUNTIME_PERMS_H diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 4762fc555dc..415e6cfa72d 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -6193,6 +6193,15 @@ void LLSelectMgr::processObjectPropertiesFamily(LLMessageSystem* msg, void** use node->mCategory = category; node->mName.assign(name); node->mDescription.assign(desc); + + LLViewerObject* obj = node->getObject(); + if (obj && LLViewerObject::isObjectInPendingUpdate(owner_id, obj)) + { + // current response doesn't return modify permissions flags, + // so we should request it separately if needed + obj->requestObjectUpdate(); + } + } dialog_refresh_all(); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index f3cfbd9565b..6e18bb979a7 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -135,9 +135,13 @@ void LLSpatialGroup::clearDrawMap() mDrawMap.clear(); } -bool LLSpatialGroup::isHUDGroup() +bool LLSpatialGroup::isHUDGroup() const { - return getSpatialPartition() && getSpatialPartition()->isHUDPartition() ; + if (hasState(DEAD)) + return false; + + LLSpatialPartition* part = (LLSpatialPartition*)mSpatialPartition; + return part && part->isHUDPartition(); } void LLSpatialGroup::validate() diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index d8a94c88354..4b312b15978 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -264,7 +264,7 @@ class LLSpatialGroup : public LLOcclusionCullingGroup LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part); - bool isHUDGroup() ; + bool isHUDGroup() const; void clearDrawMap(); void validate(); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 1a7ce74ccc6..8c8734b52f4 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -875,7 +875,7 @@ std::string LLTextureCache::getTextureFileName(const LLUUID& id) //debug bool LLTextureCache::isInCache(const LLUUID& id) { - LLMutexLock lock(&mHeaderMutex); + LLMutexLock lock(&mHeaderIDMapMutex); id_map_t::const_iterator iter = mHeaderIDMap.find(id); return (iter != mHeaderIDMap.end()) ; @@ -991,6 +991,8 @@ void LLTextureCache::setReadOnly(bool read_only) // Returns the unused amount of max_size if any S64 LLTextureCache::initCache(ELLPath location, S64 max_size, bool texture_cache_mismatch) { + LL_PROFILE_ZONE_SCOPED; + llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized. S64 entries_size = (max_size * 36) / 100; //0.36 * max_size @@ -1115,10 +1117,13 @@ S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create { S32 idx = -1; - id_map_t::iterator iter1 = mHeaderIDMap.find(id); - if (iter1 != mHeaderIDMap.end()) { - idx = iter1->second; + LLMutexLock lock(&mHeaderIDMapMutex); + id_map_t::iterator iter1 = mHeaderIDMap.find(id); + if (iter1 != mHeaderIDMap.end()) + { + idx = iter1->second; + } } if (idx < 0) @@ -1146,10 +1151,19 @@ S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create // Erase entry from LRU regardless mLRU.erase(curiter2); // Look up entry and use it if it is valid - id_map_t::iterator iter3 = mHeaderIDMap.find(oldid); - if (iter3 != mHeaderIDMap.end() && iter3->second >= 0) + + S32 found_idx = -1; { - idx = iter3->second; + LLMutexLock lock(&mHeaderIDMapMutex); + id_map_t::iterator iter3 = mHeaderIDMap.find(oldid); + if (iter3 != mHeaderIDMap.end() && iter3->second >= 0) + { + found_idx = iter3->second; + } + } + if (found_idx >= 0) + { + idx = found_idx; removeCachedTexture(oldid) ;//remove the existing cached texture to release the entry index. break; } @@ -1285,7 +1299,10 @@ bool LLTextureCache::updateEntry(S32& idx, Entry& entry, S32 new_image_size, S32 bool update_header = false ; if(entry.mImageSize < 0) //is a brand-new entry { - mHeaderIDMap[entry.mID] = idx; + { + LLMutexLock lock(&mHeaderIDMapMutex); + mHeaderIDMap[entry.mID] = idx; + } mTexturesSizeMap[entry.mID] = new_body_size ; mTexturesSizeTotal += new_body_size ; @@ -1323,8 +1340,8 @@ bool LLTextureCache::updateEntry(S32& idx, Entry& entry, S32 new_image_size, S32 U32 LLTextureCache::openAndReadEntries(std::vector& entries) { + LLMutexLock lock(&mHeaderIDMapMutex); U32 num_entries = mHeaderEntriesInfo.mEntries; - mHeaderIDMap.clear(); mTexturesSizeMap.clear(); mFreeList.clear(); @@ -1618,7 +1635,10 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) LLFile::rmdir(mTexturesDirName); } } - mHeaderIDMap.clear(); + { + LLMutexLock lock(&mHeaderIDMapMutex); + mHeaderIDMap.clear(); + } mTexturesSizeMap.clear(); mTexturesSizeTotal = 0; mFreeList.clear(); @@ -1665,6 +1685,7 @@ void LLTextureCache::purgeTexturesLazy(F32 time_limit_sec) { if (iter1->second > 0) { + LLMutexLock lock(&mHeaderIDMapMutex); id_map_t::iterator iter2 = mHeaderIDMap.find(iter1->first); if (iter2 != mHeaderIDMap.end()) { @@ -1706,8 +1727,13 @@ void LLTextureCache::purgeTexturesLazy(F32 time_limit_sec) Entry entry = mPurgeEntryList.back().second; mPurgeEntryList.pop_back(); // make sure record is still valid - id_map_t::iterator iter_header = mHeaderIDMap.find(entry.mID); - if (iter_header != mHeaderIDMap.end() && iter_header->second == idx) + bool remove_entry = false; + { + LLMutexLock lock(&mHeaderIDMapMutex); + id_map_t::iterator iter_header = mHeaderIDMap.find(entry.mID); + remove_entry = (iter_header != mHeaderIDMap.end() && iter_header->second == idx); + } + if (remove_entry) { std::string tex_filename = getTextureFileName(entry.mID); removeEntry(idx, entry, tex_filename); @@ -1750,6 +1776,7 @@ void LLTextureCache::purgeTextures(bool validate) { if (iter1->second > 0) { + LLMutexLock lock(&mHeaderIDMapMutex); id_map_t::iterator iter2 = mHeaderIDMap.find(iter1->first); if (iter2 != mHeaderIDMap.end()) { @@ -2004,7 +2031,7 @@ LLPointer LLTextureCache::readFromFastCache(const LLUUID& id, S32& d { U32 offset; { - LLMutexLock lock(&mHeaderMutex); + LLMutexLock lock(&mHeaderIDMapMutex); id_map_t::const_iterator iter = mHeaderIDMap.find(id); if(iter == mHeaderIDMap.end()) { @@ -2018,9 +2045,10 @@ LLPointer LLTextureCache::readFromFastCache(const LLUUID& id, S32& d U8* data; S32 head[4]; { + LL_PROFILE_ZONE_NAMED("Read fast cache"); LLMutexLock lock(&mFastCacheMutex); - openFastCache(); + openFastCache(); // only reopens if needed, lasts 10 seconds mFastCachep->seek(APR_SET, offset); @@ -2051,7 +2079,9 @@ LLPointer LLTextureCache::readFromFastCache(const LLUUID& id, S32& d closeFastCache(); } - LLPointer raw = new LLImageRaw(data, head[0], head[1], head[2], true); + + // directly construct image from new buffer. + LLPointer raw = new LLImageRaw(data, head[0], head[1], head[2], true /*take ownership*/); return raw; } @@ -2229,7 +2259,10 @@ void LLTextureCache::removeCachedTexture(const LLUUID& id) mTexturesSizeTotal -= mTexturesSizeMap[id] ; mTexturesSizeMap.erase(id); } - mHeaderIDMap.erase(id); + { + LLMutexLock lock(&mHeaderIDMapMutex); + mHeaderIDMap.erase(id); + } // We are inside header's mutex so mHeaderAPRFilePoolp is safe to use, // but getLocalAPRFilePool() is not safe, it might be in use by worker LLAPRFile::remove(getTextureFileName(id), mHeaderAPRFilePoolp); @@ -2260,7 +2293,10 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) entry.mImageSize = -1; entry.mBodySize = 0; - mHeaderIDMap.erase(entry.mID); + { + LLMutexLock lock(&mHeaderIDMapMutex); + mHeaderIDMap.erase(entry.mID); + } mTexturesSizeMap.erase(entry.mID); mFreeList.insert(idx); } diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index faf722dc8f6..a09bcc1572c 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -148,7 +148,7 @@ class LLTextureCache : public LLWorkerThread U32 getMaxEntries() { return sCacheMaxEntries; }; bool isInCache(const LLUUID& id) ; bool isInLocal(const LLUUID& id) ; //not thread safe at the moment - + LLMutex* getFastCacheMutex() { return &mFastCacheMutex; } protected: // Accessed by LLTextureCacheWorker std::string getLocalFileName(const LLUUID& id); @@ -194,6 +194,7 @@ class LLTextureCache : public LLWorkerThread // Internal LLMutex mWorkersMutex; LLMutex mHeaderMutex; + LLMutex mHeaderIDMapMutex; // To avoid deadlocks, never lock mFastCacheMutex after mHeaderIDMapMutex. LLMutex mListMutex; LLMutex mFastCacheMutex; LLAPRFile* mHeaderAPRFile; diff --git a/indra/newview/lltoastscriptquestion.cpp b/indra/newview/lltoastscriptquestion.cpp index 25dc0982b8d..55e178e0845 100644 --- a/indra/newview/lltoastscriptquestion.cpp +++ b/indra/newview/lltoastscriptquestion.cpp @@ -48,7 +48,12 @@ bool LLToastScriptQuestion::postBuild() LLTextBox* mFooter = getChild("bottom_info_message"); mMessage->setValue(mNotification->getMessage()); - mFooter->setValue(mNotification->getFooter()); + std::string footer = mNotification->getFooter(); + mFooter->setValue(footer); + if (footer.empty()) + { + mFooter->setVisible(false); + } snapToMessageHeight(); @@ -78,21 +83,69 @@ void LLToastScriptQuestion::snapToMessageHeight() if (mMessage->getVisible() && mFooter->getVisible()) { - S32 heightDelta = 0; - S32 maxTextHeight = (mMessage->getFont()->getLineHeight() * MAX_LINES_COUNT) + S32 height_delta = 0; + S32 max_text_height = (mMessage->getFont()->getLineHeight() * MAX_LINES_COUNT) + (mFooter->getFont()->getLineHeight() * MAX_LINES_COUNT); - LLRect messageRect = mMessage->getRect(); - LLRect footerRect = mFooter->getRect(); + LLRect message_rect = mMessage->getRect(); + + S32 old_message_height = message_rect.getHeight(); + S32 new_message_height = mMessage->getTextBoundingRect().getHeight(); + S32 new_footer_height = mFooter->getTextBoundingRect().getHeight(); + + constexpr S32 FOOTER_PADDING = 8; // new height should include padding for newly added footer + S32 required_text_height = new_message_height + new_footer_height + FOOTER_PADDING; + S32 new_text_height = llmin(required_text_height, max_text_height); + + // Footer was invisible, so use old_message_height for old height + height_delta = new_text_height - old_message_height; + + reshape( getRect().getWidth(), llmax(getRect().getHeight() + height_delta, MIN_PANEL_HEIGHT)); + + // Floater was resized, now resize and shift children + // Message follows top, so it's top is in a correct position, but needs to be resized down + S32 message_delta = new_message_height - old_message_height; + message_rect = mMessage->getRect(); // refresh since it might have changed after reshape + message_rect.mBottom = message_rect.mBottom - message_delta; + mMessage->setRect(message_rect); + mMessage->needsReflow(); + // Button panel should stay the same size, just translate it + LLPanel* panel = getChild("buttons_panel"); + panel->translate(0, -message_delta); + // Footer should be both moved and resized + LLRect footer_rect = mFooter->getRect(); + footer_rect.mTop = footer_rect.mTop - message_delta; + footer_rect.mBottom = footer_rect.mTop - new_footer_height; + mFooter->setRect(footer_rect); + mFooter->needsReflow(); + } + else if (mMessage->getVisible()) + { + S32 height_delta = 0; + S32 max_text_height = (mMessage->getFont()->getLineHeight() * MAX_LINES_COUNT); + + LLRect message_rect = mMessage->getRect(); + + S32 old_message_height = message_rect.getHeight(); + S32 new_message_height = mMessage->getTextBoundingRect().getHeight(); - S32 oldTextHeight = messageRect.getHeight() + footerRect.getHeight(); + S32 new_text_height = llmin(new_message_height, max_text_height); - S32 requiredTextHeight = mMessage->getTextBoundingRect().getHeight() + mFooter->getTextBoundingRect().getHeight(); - S32 newTextHeight = llmin(requiredTextHeight, maxTextHeight); + // Footer was invisible, so use old_message_height for old height + height_delta = new_text_height - old_message_height; - heightDelta = newTextHeight - oldTextHeight - heightDelta; + reshape(getRect().getWidth(), llmax(getRect().getHeight() + height_delta, MIN_PANEL_HEIGHT)); - reshape( getRect().getWidth(), llmax(getRect().getHeight() + heightDelta, MIN_PANEL_HEIGHT)); + // Floater was resized, now resize and shift children + // Message follows top, so it's top is in a correct position, but needs to be resized down + S32 message_delta = new_message_height - old_message_height; + message_rect = mMessage->getRect(); // refresh since it might have changed after reshape + message_rect.mBottom = message_rect.mBottom - message_delta; + mMessage->setRect(message_rect); + mMessage->needsReflow(); + // Button panel should stay the same size, just translate it + LLPanel* panel = getChild("buttons_panel"); + panel->translate(0, -message_delta); } } diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index f78ff2226c2..5e2d91d31e8 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -775,7 +775,7 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, bool drop, if (!handled) { // Disallow drag and drop to 3D from the marketplace - const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); if (marketplacelistings_id.notNull()) { for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++) diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp index 5ccda7d4eb7..3bd459f5b08 100644 --- a/indra/newview/lltoolselect.cpp +++ b/indra/newview/lltoolselect.cpp @@ -55,17 +55,17 @@ LLToolSelect::LLToolSelect( LLToolComposite* composite ) : LLTool( std::string("Select"), composite ), mIgnoreGroup( false ) { - } +} // True if you selected an object. bool LLToolSelect::handleMouseDown(S32 x, S32 y, MASK mask) { // do immediate pick query bool pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); - bool pick_transparent = gSavedSettings.getBOOL("SelectInvisibleObjects"); - bool pick_reflection_probe = gSavedSettings.getBOOL("SelectReflectionProbes"); + static LLCachedControl select_invisible_objects(gSavedSettings, "SelectInvisibleObjects"); + static LLCachedControl select_reflection_probes(gSavedSettings, "SelectReflectionProbes"); - mPick = gViewerWindow->pickImmediate(x, y, pick_transparent, pick_rigged, false, true, pick_reflection_probe); + mPick = gViewerWindow->pickImmediate(x, y, select_invisible_objects, pick_rigged, false, true, select_reflection_probes); // Pass mousedown to agent LLTool::handleMouseDown(x, y, mask); @@ -73,7 +73,6 @@ bool LLToolSelect::handleMouseDown(S32 x, S32 y, MASK mask) return mPick.getObject().notNull(); } - // static LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pick, bool ignore_group, bool temp_select, bool select_root) { diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index aa0cbac91fd..a7441febd95 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -398,18 +398,12 @@ void init_audio() void audio_update_volume(bool force_update) { - F32 master_volume = gSavedSettings.getF32("AudioLevelMaster"); - bool mute_audio = gSavedSettings.getBOOL("MuteAudio"); - - LLProgressView* progress = gViewerWindow->getProgressView(); - bool progress_view_visible = false; - - if (progress) - { - progress_view_visible = progress->getVisible(); - } + static LLCachedControl master_volume(gSavedSettings, "AudioLevelMaster"); + static LLCachedControl mute_audio_setting(gSavedSettings, "MuteAudio"); + static LLCachedControl mute_when_minimized(gSavedSettings, "MuteWhenMinimized"); + bool mute_audio = mute_audio_setting(); - if (!gViewerWindow->getActive() && gSavedSettings.getBOOL("MuteWhenMinimized")) + if (!gViewerWindow->getActive() && mute_when_minimized()) { mute_audio = true; } @@ -419,7 +413,7 @@ void audio_update_volume(bool force_update) { // Sound Effects - gAudiop->setMasterGain ( master_volume ); + gAudiop->setMasterGain (master_volume()); const F32 AUDIO_LEVEL_DOPPLER = 1.f; gAudiop->setDopplerFactor(AUDIO_LEVEL_DOPPLER); @@ -435,6 +429,7 @@ void audio_update_volume(bool force_update) gAudiop->setRolloffFactor(AUDIO_LEVEL_UNDERWATER_ROLLOFF); } + bool progress_view_visible = gViewerWindow->getShowProgress(); gAudiop->setMuted(mute_audio || progress_view_visible); //Play any deferred sounds when unmuted @@ -448,13 +443,21 @@ void audio_update_volume(bool force_update) audio_update_wind(true); } + static LLCachedControl mute_sounds(gSavedSettings, "MuteSounds"); + static LLCachedControl mute_ui(gSavedSettings, "MuteUI"); + static LLCachedControl mute_ambient(gSavedSettings, "MuteAmbient"); + static LLCachedControl mute_music(gSavedSettings, "MuteMusic"); + static LLCachedControl al_sfx(gSavedSettings, "AudioLevelSFX"); + static LLCachedControl al_ui(gSavedSettings, "AudioLevelUI"); + static LLCachedControl al_ambient(gSavedSettings, "AudioLevelAmbient"); + static LLCachedControl al_music(gSavedSettings, "AudioLevelMusic"); // handle secondary gains gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_SFX, - gSavedSettings.getBOOL("MuteSounds") ? 0.f : gSavedSettings.getF32("AudioLevelSFX")); + mute_sounds() ? 0.f : al_sfx()); gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_UI, - gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI")); + mute_ui() ? 0.f : al_ui()); gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_AMBIENT, - gSavedSettings.getBOOL("MuteAmbient") ? 0.f : gSavedSettings.getF32("AudioLevelAmbient")); + mute_ambient() ? 0.f : al_ambient()); // Streaming Music @@ -464,31 +467,29 @@ void audio_update_volume(bool force_update) LLViewerAudio::getInstance()->setForcedTeleportFade(false); } - F32 music_volume = gSavedSettings.getF32("AudioLevelMusic"); - bool music_muted = gSavedSettings.getBOOL("MuteMusic"); F32 fade_volume = LLViewerAudio::getInstance()->getFadeVolume(); - music_volume = mute_volume * master_volume * music_volume * fade_volume; - gAudiop->setInternetStreamGain (music_muted ? 0.f : music_volume); + F32 music_volume = mute_volume * master_volume * al_music() * fade_volume; + gAudiop->setInternetStreamGain (mute_music() ? 0.f : music_volume); } // Streaming Media - F32 media_volume = gSavedSettings.getF32("AudioLevelMedia"); - bool media_muted = gSavedSettings.getBOOL("MuteMedia"); - media_volume = mute_volume * master_volume * media_volume; - LLViewerMedia::getInstance()->setVolume( media_muted ? 0.0f : media_volume ); + static LLCachedControl media_muted(gSavedSettings, "MuteMedia"); + static LLCachedControl media_volume(gSavedSettings, "AudioLevelMedia"); + LLViewerMedia::getInstance()->setVolume( media_muted() ? 0.0f : (mute_volume * master_volume() * media_volume())); // Voice, this is parametric singleton, it gets initialized when ready if (LLVoiceClient::instanceExists()) { - F32 voice_volume = gSavedSettings.getF32("AudioLevelVoice"); - voice_volume = mute_volume * master_volume * voice_volume; - bool voice_mute = gSavedSettings.getBOOL("MuteVoice"); + static LLCachedControl voice_mute(gSavedSettings, "MuteVoice"); + static LLCachedControl voice_volume_setting(gSavedSettings, "AudioLevelVoice"); + static LLCachedControl voice_mic_setting(gSavedSettings, "AudioLevelMic"); + F32 voice_volume = mute_volume * master_volume() * voice_volume_setting(); LLVoiceClient *voice_inst = LLVoiceClient::getInstance(); - voice_inst->setVoiceVolume(voice_mute ? 0.f : voice_volume); - voice_inst->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic")); + voice_inst->setVoiceVolume(voice_mute() ? 0.f : voice_volume); + voice_inst->setMicGain(voice_mute() ? 0.f : voice_mic_setting()); - if (!gViewerWindow->getActive() && (gSavedSettings.getBOOL("MuteWhenMinimized"))) + if (!gViewerWindow->getActive() && mute_when_minimized()) { voice_inst->setMuteMic(true); } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 8b4b508d7c5..0c93b247510 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -813,6 +813,7 @@ void setting_setup_signal_listener(LLControlGroup& group, const std::string& set void settings_setup_listeners() { + LL_PROFILE_ZONE_SCOPED; setting_setup_signal_listener(gSavedSettings, "FirstPersonAvatarVisible", handleRenderAvatarMouselookChanged); setting_setup_signal_listener(gSavedSettings, "RenderFarClip", handleRenderFarClipChanged); setting_setup_signal_listener(gSavedSettings, "RenderTerrainScale", handleTerrainScaleChanged); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 35ac7919ac5..9dfa9a0efd2 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -576,9 +576,9 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) LLImageGL::updateStats(gFrameTimeSeconds); static LLCachedControl avatar_name_tag_mode(gSavedSettings, "AvatarNameTagMode", 1); - static LLCachedControl name_tag_show_group_titles(gSavedSettings, "NameTagShowGroupTitles", true); + static LLCachedControl name_tag_show_group_titles(gSavedSettings, "GroupTitlesTagMode", 2 /*all group tags*/); LLVOAvatar::sRenderName = avatar_name_tag_mode; - LLVOAvatar::sRenderGroupTitles = name_tag_show_group_titles && avatar_name_tag_mode > 0; + LLVOAvatar::sRenderGroupTitles = avatar_name_tag_mode > 0 ? name_tag_show_group_titles : 0; gPipeline.mBackfaceCull = true; gFrameCount++; diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index ab5235c3ad2..82fc4c6d87f 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -44,7 +44,6 @@ #include "llfloateravatarrendersettings.h" #include "llfloateravatartextures.h" #include "llfloaterbanduration.h" -#include "llfloaterbigpreview.h" #include "llfloaterbeacons.h" #include "llfloaterbuildoptions.h" #include "llfloaterbulkpermission.h" @@ -120,7 +119,6 @@ #include "llfloaterpay.h" #include "llfloaterperformance.h" #include "llfloaterperms.h" -#include "llfloaterpostprocess.h" #include "llfloaterpreference.h" #include "llfloaterpreferencesgraphicsadvanced.h" #include "llfloaterpreferenceviewadvanced.h" @@ -143,7 +141,6 @@ #include "llfloatersidepanelcontainer.h" #include "llfloaterslapptest.h" #include "llfloatersnapshot.h" -#include "llfloatersounddevices.h" #include "llfloaterspellchecksettings.h" #include "llfloatertelehub.h" #include "llfloatertestinspectors.h" @@ -154,7 +151,6 @@ #include "llfloatertoybox.h" #include "llfloatertranslationsettings.h" #include "llfloateruipreview.h" -#include "llfloatervoiceeffect.h" #include "llfloaterwebcontent.h" #include "llfloatervoicevolume.h" #include "llfloaterwhitelistentry.h" @@ -370,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); @@ -499,7 +494,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater); LLFloaterReg::add("settings_color", "floater_settings_color.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("scene_load_stats", "floater_scene_load_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); @@ -512,8 +506,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("slapp_test", "floater_test_slapp.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("big_preview", "floater_big_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterUIPreviewUtil::registerFloater(); LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); LLFloaterReg::add("upload_anim_anim", "floater_animation_anim_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); @@ -522,8 +514,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("upload_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); - LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("window_size", "floater_window_size.xml", &LLFloaterReg::build); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index bb956d455fd..a77b9f6103f 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -663,9 +663,10 @@ void LLViewerMedia::updateMedia(void *dummy_arg) LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE); llassert(!gCubeSnapshot); + static LLCachedControl use_read_thread(gSavedSettings, "PluginUseReadThread", true); // Enable/disable the plugin read thread - LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); + LLPluginProcessParent::setUseReadThread(use_read_thread()); // SL-16418 We can't call LLViewerMediaImpl->update() if we are in the state of shutting down. if(LLApp::isExiting()) @@ -2189,16 +2190,19 @@ void LLViewerMediaImpl::updateVolume() if (mProximityCamera > 0) { - if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMax")) + static LLCachedControl media_rolloff_min(gSavedSettings, "MediaRollOffMin"); + static LLCachedControl media_rolloff_max(gSavedSettings, "MediaRollOffMax"); + static LLCachedControl media_rolloff_rate(gSavedSettings, "MediaRollOffRate"); + if (mProximityCamera > media_rolloff_max()) { volume = 0; } - else if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMin")) + else if (mProximityCamera > media_rolloff_min()) { // attenuated_volume = 1 / (roll_off_rate * (d - min))^2 // the +1 is there so that for distance 0 the volume stays the same - F64 adjusted_distance = mProximityCamera - gSavedSettings.getF32("MediaRollOffMin"); - F64 attenuation = 1.0 + (gSavedSettings.getF32("MediaRollOffRate") * adjusted_distance); + F64 adjusted_distance = mProximityCamera - media_rolloff_min(); + F64 attenuation = 1.0 + (media_rolloff_rate() * adjusted_distance); attenuation = 1.0 / (attenuation * attenuation); // the attenuation multiplier should never be more than one since that would increase volume volume = volume * (F32)llmin(1.0, attenuation); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index c9f10d845fa..dbcf4fbbf41 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -140,7 +140,7 @@ #include "llwindow.h" #include "llpathfindingmanager.h" #include "llstartup.h" -#include "boost/unordered_map.hpp" +#include #include #include #include @@ -153,7 +153,7 @@ using namespace LLAvatarAppearanceDefines; typedef LLPointer LLViewerObjectPtr; -static boost::unordered_map sDefaultItemLabels; +static std::unordered_map sDefaultItemLabels; LLVOAvatar* find_avatar_from_object(LLViewerObject* object); LLVOAvatar* find_avatar_from_object(const LLUUID& object_id); @@ -413,7 +413,23 @@ static LLSLMMenuUpdater* gSLMMenuUpdater = NULL; LLSLMMenuUpdater::LLSLMMenuUpdater() { - mMarketplaceListingsItem = gMenuHolder->getChild("MarketplaceListings")->getHandle(); + LLView* me_menu = gMenuHolder->findChild("Me"); + if (!me_menu) + { + LLError::LLUserWarningMsg::showMissingFiles(); + LL_ERRS() << "Can't find 'Me' menu in 'menu_viewer'" << LL_ENDL; + return; + } + + LLView* marketplace_listings = me_menu->findChild("MarketplaceListings"); + if (!marketplace_listings) + { + LLError::LLUserWarningMsg::showMissingFiles(); + LL_ERRS() << "Can't find 'MarketplaceListings' in 'Me' menu" << LL_ENDL; + return; + } + + mMarketplaceListingsItem = marketplace_listings->getHandle(); } void LLSLMMenuUpdater::setMerchantMenu() { @@ -425,7 +441,7 @@ void LLSLMMenuUpdater::setMerchantMenu() LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings"); gToolBarView->enableCommand(command->id(), true); - const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID marketplacelistings_id = gInventory.getMarketplaceListingsUUID(); if (marketplacelistings_id.isNull()) { U32 mkt_status = LLMarketplaceData::instance().getSLMStatus(); @@ -473,6 +489,8 @@ void check_merchant_status(bool force) void init_menus() { + LL_PROFILE_ZONE_SCOPED; + // Initialize actions initialize_menus(); @@ -549,7 +567,29 @@ void init_menus() color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); } - LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder"); + LLView* menu_stack = gViewerWindow->getMainView()->findChildView("menu_stack"); + if (!menu_stack) + { + LLError::LLUserWarningMsg::showMissingFiles(); + LL_ERRS() << "Can't find menu_stack in main_view" << LL_ENDL; + return; + } + + LLView* status_bar_container = menu_stack->findChildView("status_bar_container"); + if (!status_bar_container) + { + LLError::LLUserWarningMsg::showMissingFiles(); + LL_ERRS() << "Can't find status_bar_container in main_view" << LL_ENDL; + return; + } + + LLView* menu_bar_holder = status_bar_container->findChildView("menu_bar_holder"); + if (!menu_bar_holder) + { + LLError::LLUserWarningMsg::showMissingFiles(); + LL_ERRS() << "Can't find status_bar_container in main_view" << LL_ENDL; + return; + } gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); gMenuBarView->setRect(LLRect(0, menu_bar_holder->getRect().mTop, 0, menu_bar_holder->getRect().mTop - MENU_BAR_HEIGHT)); @@ -563,8 +603,33 @@ void init_menus() // *TODO:Also fix cost in llfolderview.cpp for Inventory menus const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); - gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", sound_upload_cost_str); - gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", animation_upload_cost_str); + + LLView* main_upload_menu = gMenuHolder->findChild("Upload"); + if (!main_upload_menu) + { + LLError::LLUserWarningMsg::showMissingFiles(); + LL_ERRS() << "Can't find 'Upload' menu in 'menu_viewer'" << LL_ENDL; + return; + } + + LLView* upload_sound = main_upload_menu->findChild("Upload Sound"); + if (!upload_sound) + { + LLError::LLUserWarningMsg::showMissingFiles(); + LL_ERRS() << "Can't find 'Upload Sound' menu item in 'Upload' menu" << LL_ENDL; + return; + } + upload_sound->setLabelArg("[COST]", sound_upload_cost_str); + + LLView* upload_anim = main_upload_menu->findChild("Upload Animation"); + if (!upload_anim) + { + LLError::LLUserWarningMsg::showMissingFiles(); + LL_ERRS() << "Can't find 'Upload Animation' menu item in 'Upload' menu" << LL_ENDL; + return; + } + upload_anim->setLabelArg("[COST]", animation_upload_cost_str); + gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", true); gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", true); @@ -572,13 +637,6 @@ void init_menus() gDetachAvatarMenu = gMenuHolder->getChild("Avatar Detach", true); gDetachHUDAvatarMenu = gMenuHolder->getChild("Avatar Detach HUD", true); - // Don't display the Memory console menu if the feature is turned off - LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild("Memory", true); - if (memoryMenu) - { - memoryMenu->setVisible(false); - } - gMenuBarView->createJumpKeys(); // Let land based option enable when parcel changes @@ -2959,11 +3017,45 @@ void handle_object_show_original() show_item_original(object->getAttachmentItemID()); } +void handle_object_set_favorite(const LLSD& userdata) +{ + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) + { + return; + } + LLViewerObject *parent = (LLViewerObject*)object->getParent(); + while (parent) + { + if(parent->isAvatar()) + { + break; + } + object = parent; + parent = (LLViewerObject*)parent->getParent(); + } + if (!object || object->isAvatar()) + { + return; + } + + LLUUID item_id = gInventory.getLinkedItemID(object->getAttachmentItemID()); + + std::string action = userdata.asString(); + if (action == "Add") + { + set_favorite(item_id, true); + } + if (action == "Remove") + { + set_favorite(item_id, false); + } +} static void init_default_item_label(LLUICtrl* ctrl) { const std::string& item_name = ctrl->getName(); - boost::unordered_map::iterator it = sDefaultItemLabels.find(item_name); + std::unordered_map::iterator it = sDefaultItemLabels.find(item_name); if (it == sDefaultItemLabels.end()) { // *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value @@ -2979,7 +3071,7 @@ static void init_default_item_label(LLUICtrl* ctrl) static LLStringExplicit get_default_item_label(const std::string& item_name) { LLStringExplicit res(""); - boost::unordered_map::iterator it = sDefaultItemLabels.find(item_name); + std::unordered_map::iterator it = sDefaultItemLabels.find(item_name); if (it != sDefaultItemLabels.end()) { res = it->second; @@ -3015,6 +3107,41 @@ bool enable_object_touch(LLUICtrl* ctrl) return new_value; }; +bool enable_object_favorite(const LLSD& userdata) +{ + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) + { + return false; + } + LLViewerObject* parent = (LLViewerObject*)object->getParent(); + while (parent) + { + if (parent->isAvatar()) + { + break; + } + object = parent; + parent = (LLViewerObject*)parent->getParent(); + } + if (!object || object->isAvatar()) + { + return false; + } + + std::string action = userdata.asString(); + LLUUID item_id = gInventory.getLinkedItemID(object->getAttachmentItemID()); + if (action == "Add") + { + return !get_is_favorite(item_id); + } + if (action == "Remove") + { + return get_is_favorite(item_id); + } + return false; +} + //void label_touch(std::string& label, void*) //{ // LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); @@ -9499,17 +9626,6 @@ class LLWorldEnableEnvPreset : public view_listener_t } }; - -/// Post-Process callbacks -class LLWorldPostProcess : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("env_post_process"); - return true; - } -}; - class LLWorldCheckBanLines : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -9692,6 +9808,8 @@ void initialize_spellcheck_menu() void initialize_menus() { + LL_PROFILE_ZONE_SCOPED; + // A parameterized event handler used as ctrl-8/9/0 zoom controls below. class LLZoomer : public view_listener_t { @@ -9801,7 +9919,6 @@ void initialize_menus() view_listener_t::addMenu(new LLWorldEnableEnvSettings(), "World.EnableEnvSettings"); view_listener_t::addMenu(new LLWorldEnvPreset(), "World.EnvPreset"); view_listener_t::addMenu(new LLWorldEnableEnvPreset(), "World.EnableEnvPreset"); - view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); view_listener_t::addMenu(new LLWorldCheckBanLines() , "World.CheckBanLines"); view_listener_t::addMenu(new LLWorldShowBanLines() , "World.ShowBanLines"); @@ -10113,6 +10230,7 @@ void initialize_menus() view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); commit.add("Object.Touch", boost::bind(&handle_object_touch)); commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original)); + commit.add("Object.SetFavorite", boost::bind(&handle_object_set_favorite, _2)); commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); commit.add("Object.Delete", boost::bind(&handle_object_delete)); view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar"); @@ -10141,6 +10259,7 @@ void initialize_menus() enable.add("Object.EnableEditGLTFMaterial", boost::bind(&enable_object_edit_gltf_material)); enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1)); + enable.add("Object.EnableFavorites", boost::bind(&enable_object_favorite, _2)); enable.add("Object.EnableDelete", boost::bind(&enable_object_delete)); enable.add("Object.EnableWear", boost::bind(&object_is_wearable)); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 36e8e27800f..5d8bd452186 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5749,28 +5749,40 @@ void process_script_question(LLMessageSystem *msg, void **user_data) args["NAME"] = clean_owner_name; S32 known_questions = 0; bool has_not_only_debit = questions ^ SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_DEBIT].permbit; + bool caution_enabled = gSavedSettings.getBOOL("PermissionsCautionEnabled"); // check the received permission flags against each permission + std::string warning_msg; for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS) { if (questions & script_perm.permbit) { - count++; known_questions |= script_perm.permbit; // check whether permission question should cause special caution dialog caution |= (script_perm.caution); - if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit) + // Cautions go into top part of the dialog, questions go into the footer + if (caution_enabled && script_perm.caution) + { + warning_msg += "\n" + LLTrans::getString(script_perm.question + "Caution") + "\n"; continue; + } if (LLTrans::getString(script_perm.question).empty()) { continue; } - script_question += " " + LLTrans::getString(script_perm.question) + "\n"; + count++; + script_question += "\n " + LLTrans::getString(script_perm.question); } } + if (!warning_msg.empty()) + { + LLStringUtil::format(warning_msg, args); + args["WARNINGS"] = warning_msg; + } + args["QUESTIONS"] = script_question; if (known_questions != questions) @@ -5795,12 +5807,12 @@ void process_script_question(LLMessageSystem *msg, void **user_data) // check whether cautions are even enabled or not const char* notification = "ScriptQuestion"; - if(caution && gSavedSettings.getBOOL("PermissionsCautionEnabled")) + if(caution && caution_enabled) { - args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n\n" + script_question : ""; + args["FOOTERTEXT"] = (count > 0) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n" + script_question : ""; notification = "ScriptQuestionCaution"; } - else if(experienceid.notNull()) + else if (experienceid.notNull()) { payload["experience"]=experienceid; LLExperienceCache::instance().get(experienceid, boost::bind(process_script_experience_details, _1, args, payload)); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 1675c44c5ce..db1ef54ffaf 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -130,6 +130,7 @@ F64Seconds LLViewerObject::sPhaseOutUpdateInterpolationTime(2.0); // For motio F64Seconds LLViewerObject::sMaxRegionCrossingInterpolationTime(1.0);// For motion interpolation: don't interpolate over this time on region crossing std::map LLViewerObject::sObjectDataMap; +std::unordered_map> LLViewerObject::sPendingUpdatesByOwner; // The maximum size of an object extra parameters binary (packed) block #define MAX_OBJECT_PARAMS_SIZE 1024 @@ -310,6 +311,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mAttachmentItemID(LLUUID::null), mLastUpdateType(OUT_UNKNOWN), mLastUpdateCached(false), + mExtraParameterList(LLNetworkData::PARAMS_MAX >> 4), mCachedMuteListUpdateTime(0), mCachedOwnerInMuteList(false), mRiggedAttachedWarned(false) @@ -367,15 +369,6 @@ LLViewerObject::~LLViewerObject() } // Delete memory associated with extra parameters. - std::unordered_map::iterator iter; - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) - { - if(iter->second != NULL) - { - delete iter->second->data; - delete iter->second; - } - } mExtraParameterList.clear(); for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ; @@ -529,6 +522,8 @@ void LLViewerObject::markDead() mReflectionProbe = nullptr; } + removeObjectFromPendingUpdate(this); + sNumZombieObjects++; } } @@ -1508,10 +1503,9 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, unpackParticleSource(block_num, owner_id); // Mark all extra parameters not used - std::unordered_map::iterator iter; - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + for (auto& entry : mExtraParameterList) { - iter->second->in_use = false; + if (entry.in_use) *entry.in_use = false; } // Unpack extra parameters @@ -1543,12 +1537,13 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, delete[] buffer; } - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + for (size_t i = 0; i < mExtraParameterList.size(); ++i) { - if (!iter->second->in_use) + auto& entry = mExtraParameterList[i]; + if (entry.in_use && !*entry.in_use) { // Send an update message in case it was formerly in use - parameterChanged(iter->first, iter->second->data, false, false); + parameterChanged(((U16)i + 1) << 4, entry.data, false, false); } } @@ -1850,10 +1845,9 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } // Mark all extra parameters not used - std::unordered_map::iterator iter; - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + for (auto& entry : mExtraParameterList) { - iter->second->in_use = false; + if (entry.in_use) *entry.in_use = false; } // Unpack extra params @@ -1871,12 +1865,13 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, unpackParameterEntry(param_type, &dp2); } - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + for (size_t i = 0; i < mExtraParameterList.size(); ++i) { - if (!iter->second->in_use) + auto& entry = mExtraParameterList[i]; + if (entry.in_use && !*entry.in_use) { // Send an update message in case it was formerly in use - parameterChanged(iter->first, iter->second->data, false, false); + parameterChanged(((U16)i + 1) << 4, entry.data, false, false); } } @@ -4183,7 +4178,7 @@ void LLViewerObject::boostTexturePriority(bool boost_children /* = true */) if (isSculpted() && !isMesh()) { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams *sculpt_params = getSculptParams(); if (sculpt_params) { LLUUID sculpt_id = sculpt_params->getSculptTexture(); @@ -4655,9 +4650,10 @@ const LLQuaternion LLViewerObject::getRenderRotation() const } else { - if (!mDrawable->isRoot()) + LLDrawable* parent = mDrawable->getParent(); + if (!mDrawable->isRoot() && parent) { - ret = getRotation() * LLQuaternion(mDrawable->getParent()->getWorldMatrix()); + ret = getRotation() * LLQuaternion(parent->getWorldMatrix()); } else { @@ -6494,7 +6490,7 @@ bool LLViewerObject::unpackParameterEntry(U16 param_type, LLDataPacker *dp) if (param) { param->data->unpack(*dp); - param->in_use = true; + *param->in_use = true; parameterChanged(param_type, param->data, true, false); return true; } @@ -6506,108 +6502,79 @@ bool LLViewerObject::unpackParameterEntry(U16 param_type, LLDataPacker *dp) LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 param_type) { - LLNetworkData* new_block = NULL; + LLNetworkData* new_block = nullptr; + bool* in_use = NULL; switch (param_type) { case LLNetworkData::PARAMS_FLEXIBLE: { - new_block = new LLFlexibleObjectData(); + mFlexibleObjectData = std::make_unique(); + new_block = mFlexibleObjectData.get(); + in_use = &mFlexibleObjectDataInUse; break; } case LLNetworkData::PARAMS_LIGHT: { - new_block = new LLLightParams(); + mLightParams = std::make_unique(); + new_block = mLightParams.get(); + in_use = &mLightParamsInUse; break; } case LLNetworkData::PARAMS_SCULPT: { - new_block = new LLSculptParams(); + mSculptParams = std::make_unique(); + new_block = mSculptParams.get(); + in_use = &mSculptParamsInUse; break; } case LLNetworkData::PARAMS_LIGHT_IMAGE: { - new_block = new LLLightImageParams(); + mLightImageParams = std::make_unique(); + new_block = mLightImageParams.get(); + in_use = &mLightImageParamsInUse; break; } case LLNetworkData::PARAMS_EXTENDED_MESH: { - new_block = new LLExtendedMeshParams(); + mExtendedMeshParams = std::make_unique(); + new_block = mExtendedMeshParams.get(); + in_use = &mExtendedMeshParamsInUse; break; } case LLNetworkData::PARAMS_RENDER_MATERIAL: { - new_block = new LLRenderMaterialParams(); + mRenderMaterialParams = std::make_unique(); + new_block = mRenderMaterialParams.get(); + in_use = &mRenderMaterialParamsInUse; break; } case LLNetworkData::PARAMS_REFLECTION_PROBE: { - new_block = new LLReflectionProbeParams(); + mReflectionProbeParams = std::make_unique(); + new_block = mReflectionProbeParams.get(); + in_use = &mReflectionProbeParamsInUse; break; } default: { - LL_INFOS_ONCE() << "Unknown param type: " << param_type << LL_ENDL; + LL_INFOS_ONCE() << "Unknown param type. (" << llformat("0x%2x", param_type) << ")" << LL_ENDL; break; } }; + ExtraParameter& entry = mExtraParameterList[U32(param_type >> 4) - 1]; if (new_block) { - ExtraParameter* new_entry = new ExtraParameter; - new_entry->data = new_block; - new_entry->in_use = false; // not in use yet - llassert(mExtraParameterList[param_type] == nullptr); // leak -- redundantly allocated parameter entry - mExtraParameterList[param_type] = new_entry; - return new_entry; - } - return NULL; -} - -LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntry(U16 param_type) const -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER; - std::unordered_map::const_iterator itor = mExtraParameterList.find(param_type); - if (itor != mExtraParameterList.end()) - { - return itor->second; - } - return NULL; -} - -LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntryCreate(U16 param_type) -{ - ExtraParameter* param = getExtraParameterEntry(param_type); - if (!param) - { - param = createNewParameterEntry(param_type); - } - return param; -} - -LLNetworkData* LLViewerObject::getParameterEntry(U16 param_type) const -{ - ExtraParameter* param = getExtraParameterEntry(param_type); - if (param) - { - return param->data; + entry.in_use = in_use; + *entry.in_use = false; // not in use yet + entry.data = new_block; + return &entry; } else { - return NULL; - } -} - -bool LLViewerObject::getParameterEntryInUse(U16 param_type) const -{ - ExtraParameter* param = getExtraParameterEntry(param_type); - if (param) - { - return param->in_use; - } - else - { - return false; + entry.is_invalid = true; } + return nullptr; } bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin) @@ -6615,11 +6582,11 @@ bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_ ExtraParameter* param = getExtraParameterEntryCreate(param_type); if (param) { - if (param->in_use && new_value == *(param->data)) + if (*(param->in_use) && new_value == *(param->data)) { return false; } - param->in_use = true; + *param->in_use = true; param->data->copy(new_value); parameterChanged(param_type, param->data, true, local_origin); return true; @@ -6635,22 +6602,28 @@ bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_ // Should always return true. bool LLViewerObject::setParameterEntryInUse(U16 param_type, bool in_use, bool local_origin) { - ExtraParameter* param = getExtraParameterEntryCreate(param_type); - if (param && param->in_use != in_use) + if (param_type <= LLNetworkData::PARAMS_MAX) { - param->in_use = in_use; - parameterChanged(param_type, param->data, in_use, local_origin); - return true; + ExtraParameter* param = (in_use ? getExtraParameterEntryCreate(param_type) : &getExtraParameterEntry(param_type)); + if (param && param->data && *param->in_use != in_use) + { + *param->in_use = in_use; + parameterChanged(param_type, param->data, in_use, local_origin); + return true; + } } return false; } void LLViewerObject::parameterChanged(U16 param_type, bool local_origin) { - ExtraParameter* param = getExtraParameterEntry(param_type); - if (param) + if (param_type <= LLNetworkData::PARAMS_MAX) { - parameterChanged(param_type, param->data, param->in_use, local_origin); + const ExtraParameter& param = getExtraParameterEntry(param_type); + if (param.data) + { + parameterChanged(param_type, param.data, *param.in_use, local_origin); + } } } @@ -6698,7 +6671,7 @@ void LLViewerObject::parameterChanged(U16 param_type, LLNetworkData* data, bool { if (param_type == LLNetworkData::PARAMS_RENDER_MATERIAL) { - const LLRenderMaterialParams* params = in_use ? (LLRenderMaterialParams*)getParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL) : nullptr; + const LLRenderMaterialParams* params = in_use ? getRenderMaterialParams() : nullptr; setRenderMaterialIDs(params, local_origin); } } @@ -7469,9 +7442,10 @@ const std::string& LLViewerObject::getAttachmentItemName() const LLVOAvatar* LLViewerObject::getAvatar() const { LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; - if (getControlAvatar()) + LLControlAvatar* ca = getControlAvatar(); + if (ca) { - return getControlAvatar(); + return ca; } if (isAttachment()) { @@ -7490,7 +7464,7 @@ LLVOAvatar* LLViewerObject::getAvatar() const bool LLViewerObject::hasRenderMaterialParams() const { - return getParameterEntryInUse(LLNetworkData::PARAMS_RENDER_MATERIAL); + return mRenderMaterialParamsInUse; } void LLViewerObject::setHasRenderMaterialParams(bool has_materials) @@ -7512,7 +7486,7 @@ void LLViewerObject::setHasRenderMaterialParams(bool has_materials) const LLUUID& LLViewerObject::getRenderMaterialID(U8 te) const { - LLRenderMaterialParams* param_block = (LLRenderMaterialParams*)getParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL); + const LLRenderMaterialParams* param_block = getRenderMaterialParams(); if (param_block) { return param_block->getMaterial(te); @@ -7553,7 +7527,7 @@ void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool updat start_idx = llmax(start_idx, 0); end_idx = llmin(end_idx, (S32) getNumTEs()); - LLRenderMaterialParams* param_block = (LLRenderMaterialParams*)getParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL); + LLRenderMaterialParams* param_block = getRenderMaterialParams(); if (!param_block && id.notNull()) { // block doesn't exist, but it will need to param_block = (LLRenderMaterialParams*)createNewParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL)->data; @@ -7781,6 +7755,61 @@ bool LLViewerObject::isReachable() return false; } +void LLViewerObject::markObjectsForUpdate(const LLUUID& owner_id) +{ + sPendingUpdatesByOwner.erase(owner_id); + for (S32 i = 0; i < gObjectList.getNumObjects(); ++i) + { + LLViewerObject* obj = gObjectList.getObject(i); + if (!obj || obj->isDead() || obj->isAvatar() || obj->permYouOwner()) + { + continue; + } + sPendingUpdatesByOwner[owner_id].push_back(obj); + } +} + +void LLViewerObject::removeObjectFromPendingUpdate(LLViewerObject* obj) +{ + for (auto& [owner_id, objects] : sPendingUpdatesByOwner) + { + objects.erase(std::remove(objects.begin(), objects.end(), obj), objects.end()); + } +} + +bool LLViewerObject::isObjectInPendingUpdate(const LLUUID& owner_id, LLViewerObject* obj) +{ + if (!obj) + { + return false; + } + auto it = sPendingUpdatesByOwner.find(owner_id); + if (it != sPendingUpdatesByOwner.end()) + { + const auto& objects = it->second; + return std::find(objects.begin(), objects.end(), obj) != objects.end(); + } + return false; +} + +void LLViewerObject::requestObjectUpdate() +{ + if (LLViewerRegion* regionp = getRegion()) + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RequestMultipleObjects); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU8Fast(_PREHASH_CacheMissType, 0); + msg->addU32Fast(_PREHASH_ID, getLocalID()); + msg->sendReliable(regionp->getHost()); + + removeObjectFromPendingUpdate(this); + } +} + class ObjectPhysicsProperties : public LLHTTPNode { public: diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index a9c2db60e46..465e221ae47 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -126,13 +126,15 @@ class LLViewerObject protected: virtual ~LLViewerObject(); // use unref() +private: // TomY: Provide for a list of extra parameter structures, mapped by structure name struct ExtraParameter { - bool in_use; - LLNetworkData *data; + bool is_invalid = false; + bool* in_use = nullptr; + LLNetworkData* data = nullptr; }; - std::unordered_map mExtraParameterList; + std::vector mExtraParameterList; public: typedef std::list > child_list_t; @@ -620,6 +622,11 @@ class LLViewerObject void setPhysicsDensity(F32 density); void setPhysicsRestitution(F32 restitution); + static void markObjectsForUpdate(const LLUUID& owner_id); + static void removeObjectFromPendingUpdate(LLViewerObject* obj); + static bool isObjectInPendingUpdate(const LLUUID& owner_id, LLViewerObject* obj); + void requestObjectUpdate(); + virtual void dump() const; static U32 getNumZombieObjects() { return sNumZombieObjects; } @@ -630,10 +637,16 @@ class LLViewerObject void dirtySpatialGroup() const; virtual void dirtyMesh(); - virtual LLNetworkData* getParameterEntry(U16 param_type) const; - virtual bool setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin); - virtual bool getParameterEntryInUse(U16 param_type) const; - virtual bool setParameterEntryInUse(U16 param_type, bool in_use, bool local_origin); + LLFlexibleObjectData* getFlexibleObjectData() const { return mFlexibleObjectDataInUse ? mFlexibleObjectData.get() : nullptr; } + LLLightParams* getLightParams() const { return mLightParamsInUse ? mLightParams.get() : nullptr; } + LLSculptParams* getSculptParams() const { return mSculptParamsInUse ? mSculptParams.get() : nullptr; } + LLLightImageParams* getLightImageParams() const { return mLightImageParamsInUse ? mLightImageParams.get() : nullptr; } + LLExtendedMeshParams* getExtendedMeshParams() const { return mExtendedMeshParamsInUse ? mExtendedMeshParams.get() : nullptr; } + LLRenderMaterialParams* getRenderMaterialParams() const { return mRenderMaterialParamsInUse ? mRenderMaterialParams.get() : nullptr; } + LLReflectionProbeParams* getReflectionProbeParams() const { return mReflectionProbeParamsInUse ? mReflectionProbeParams.get() : nullptr; } + + bool setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin); + bool setParameterEntryInUse(U16 param_type, bool in_use, bool local_origin); // Called when a parameter is changed virtual void parameterChanged(U16 param_type, bool local_origin); virtual void parameterChanged(U16 param_type, LLNetworkData* data, bool in_use, bool local_origin); @@ -675,8 +688,31 @@ class LLViewerObject bool isAssetInInventory(LLViewerInventoryItem* item, LLAssetType::EType type); ExtraParameter* createNewParameterEntry(U16 param_type); - ExtraParameter* getExtraParameterEntry(U16 param_type) const; - ExtraParameter* getExtraParameterEntryCreate(U16 param_type); + const ExtraParameter& getExtraParameterEntry(U16 param_type) const + { + return mExtraParameterList[U32(param_type >> 4) - 1]; + } + ExtraParameter& getExtraParameterEntry(U16 param_type) + { + return mExtraParameterList[U32(param_type >> 4) - 1]; + } + ExtraParameter* getExtraParameterEntryCreate(U16 param_type) + { + if (param_type <= LLNetworkData::PARAMS_MAX) + { + ExtraParameter& param = getExtraParameterEntry(param_type); + if (!param.is_invalid) + { + if (!param.data) + { + ExtraParameter* new_entry = createNewParameterEntry(param_type); + return new_entry; + } + return ¶m; + } + } + return nullptr; + } bool unpackParameterEntry(U16 param_type, LLDataPacker *dp); // This function checks to see if the given media URL has changed its version @@ -749,7 +785,23 @@ class LLViewerObject // Grabbed from UPDATE_FLAGS U32 mFlags; + bool mFlexibleObjectDataInUse = false, + mLightParamsInUse = false, + mSculptParamsInUse = false, + mLightImageParamsInUse = false, + mExtendedMeshParamsInUse = false, + mRenderMaterialParamsInUse = false, + mReflectionProbeParamsInUse = false; + std::unique_ptr mFlexibleObjectData; + std::unique_ptr mLightParams; + std::unique_ptr mSculptParams; + std::unique_ptr mLightImageParams; + std::unique_ptr mExtendedMeshParams; + std::unique_ptr mRenderMaterialParams; + std::unique_ptr mReflectionProbeParams; + static std::map sObjectDataMap; + static std::unordered_map> sPendingUpdatesByOwner; public: // Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties U8 mPhysicsShapeType; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 1b38fed3bb8..34e5cc9de82 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -65,6 +65,7 @@ #include "lltoolmgr.h" #include "lltoolpie.h" #include "llkeyboard.h" +#include "llmeshrepository.h" #include "u64.h" #include "llviewertexturelist.h" #include "lldatapacker.h" @@ -173,7 +174,7 @@ bool LLViewerObjectList::removeFromLocalIDTable(LLViewerObject* objectp) U32 local_id = objectp->mLocalID; U64 indexid = (((U64)objectp->mRegionIndex) << 32) | (U64)local_id; - std::map::iterator iter = mIndexAndLocalIDToUUID.find(indexid); + auto iter = mIndexAndLocalIDToUUID.find(indexid); if (iter == mIndexAndLocalIDToUUID.end()) { return false; @@ -1398,6 +1399,8 @@ void LLViewerObjectList::killAllObjects() llassert((objectp == gAgentAvatarp) || objectp->isDead()); } + gMeshRepo.unregisterAllMeshes(); + cleanDeadObjects(false); if(!mObjects.empty()) diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 547ef9fb2d4..adc90a04832 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -204,7 +204,7 @@ class LLViewerObjectList uuid_set_t mDeadObjects; - std::map > mUUIDObjectMap; + std::unordered_map > mUUIDObjectMap; //set of objects that need to update their cost uuid_set_t mStaleObjectCost; @@ -221,7 +221,7 @@ class LLViewerObjectList static U32 sSimulatorMachineIndex; std::map mIPAndPortToIndex; - std::map mIndexAndLocalIDToUUID; + std::unordered_map mIndexAndLocalIDToUUID; friend class LLViewerObject; diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h index 60e17a6f580..adfe709b04d 100644 --- a/indra/newview/llvieweroctree.h +++ b/indra/newview/llvieweroctree.h @@ -316,7 +316,6 @@ class LLOcclusionCullingGroup : public LLViewerOctreeGroup //virtual bool isRecentlyVisible() const; - LLViewerOctreePartition* getSpatialPartition()const {return mSpatialPartition;} bool isAnyRecentlyVisible() const; static U32 getNewOcclusionQueryObjectName(); diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 432da2e9905..b7940471354 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -702,6 +702,16 @@ bool LLViewerParcelMgr::allowAgentVoice() const return allowAgentVoice(gAgent.getRegion(), mAgentParcel); } +bool LLViewerParcelMgr::isVoiceRestricted() const +{ + return mAgentParcel && !mAgentParcel->getParcelFlagUseEstateVoiceChannel(); +} + +bool LLViewerParcelMgr::allowVoiceModeration() const +{ + return isVoiceRestricted() && isParcelOwnedByAgent(mAgentParcel, GP_SESSION_MODERATOR); +} + bool LLViewerParcelMgr::allowAgentVoice(const LLViewerRegion* region, const LLParcel* parcel) const { return region && region->isVoiceEnabled() @@ -881,7 +891,8 @@ LLParcel* LLViewerParcelMgr::getCollisionParcel() const void LLViewerParcelMgr::render() { - if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection") && !gDisconnected) + static LLCachedControl render_parcel_selection(gSavedSettings, "RenderParcelSelection"); + if (mSelected && mRenderSelection && render_parcel_selection() && !gDisconnected) { // Rendering is done in agent-coordinates, so need to supply // an appropriate offset to the render code. diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 8439283eb09..0d79496ccc7 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -174,6 +174,12 @@ class LLViewerParcelMgr : public LLSingleton bool allowAgentVoice() const; bool allowAgentVoice(const LLViewerRegion* region, const LLParcel* parcel) const; + // Returns true if this parcel is using private voice channel + bool isVoiceRestricted() const; + + // Can this agent moderate Nearby voice chat on this parcel? + bool allowVoiceModeration() const; + // Can this agent start flying on this parcel? // Used for parcel property icons in nav bar. bool allowAgentFly(const LLViewerRegion* region, const LLParcel* parcel) const; diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index e36ad0e722b..e023dffc03e 100755 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -63,9 +63,9 @@ LLUIColor LLViewerParcelOverlay::sForSaleColor; LLUIColor LLViewerParcelOverlay::sAuctionColor; LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_width_meters) -: mRegion( region ), - mParcelGridsPerEdge( S32( region_width_meters / PARCEL_GRID_STEP_METERS ) ), - mDirty( false ), +: mRegion(region), + mParcelGridsPerEdge(S32(region_width_meters / PARCEL_GRID_STEP_METERS)), + mDirty(false), mTimeSinceLastUpdate(), mOverlayTextureIdx(-1) { @@ -467,9 +467,9 @@ void LLViewerParcelOverlay::updatePropertyLines() { for (S32 col = 0; col < GRIDS_PER_EDGE; col++) { - U8 overlay = mOwnership[row*GRIDS_PER_EDGE+col]; + U8 overlay = mOwnership[row * GRIDS_PER_EDGE + col]; S32 colorIndex = overlay & PARCEL_COLOR_MASK; - switch(colorIndex) + switch (colorIndex) { case PARCEL_SELF: case PARCEL_GROUP: @@ -483,11 +483,11 @@ void LLViewerParcelOverlay::updatePropertyLines() const LLColor4U& color = colors[colorIndex]; - F32 left = col*GRID_STEP; - F32 right = left+GRID_STEP; + F32 left = col * GRID_STEP; + F32 right = left + GRID_STEP; - F32 bottom = row*GRID_STEP; - F32 top = bottom+GRID_STEP; + F32 bottom = row * GRID_STEP; + F32 top = bottom + GRID_STEP; // West edge if (overlay & PARCEL_WEST_LINE) @@ -528,99 +528,121 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3 Edge& edge = mEdges.back(); edge.color = color; + // Detailized rendering vertices: + // A B C D E F G + // *-*------*--------*--------*------*-* : 'outside' vertices are placed right on the border + // *------*--------*--------*------* : 'inside' vertices are shifted on LINE_WIDTH inside + + // Simplified rendering vertices: + // A G + // *-----------------------------------* + // *-----------------------------------* + F32 outside_x = start_x; F32 outside_y = start_y; - F32 outside_z = 0.f; - F32 inside_x = start_x + tick_dx; - F32 inside_y = start_y + tick_dy; - F32 inside_z = 0.f; + F32 outside_z = land.resolveHeightRegion(outside_x, outside_y); + F32 inside_x = start_x + tick_dx; + F32 inside_y = start_y + tick_dy; + F32 inside_z = land.resolveHeightRegion(inside_x, inside_y); + + auto move = [&](F32 distance) + { + outside_x += dx * distance; + outside_y += dy * distance; + outside_z = land.resolveHeightRegion(outside_x, outside_y); + inside_x += dx * distance; + inside_y += dy * distance; + inside_z = land.resolveHeightRegion(inside_x, inside_y); + }; - auto split = [&](const LLVector3& start, F32 x, F32 y, F32 z, F32 part) + auto split = [&](U32 lod, const LLVector4a& start, F32 x, F32 y, F32 z, F32 part) { - F32 new_x = start.mV[VX] + (x - start.mV[VX]) * part; - F32 new_y = start.mV[VY] + (y - start.mV[VY]) * part; - F32 new_z = start.mV[VZ] + (z - start.mV[VZ]) * part; - edge.vertices.emplace_back(new_x, new_y, new_z); + F32 new_x = start[VX] + (x - start[VX]) * part; + F32 new_y = start[VY] + (y - start[VY]) * part; + edge.pushVertex(lod, new_x, new_y, water_z, 0); }; - auto checkForSplit = [&]() + auto checkForSplit = [&](U32 lod) { - const LLVector3& last_outside = edge.vertices.back(); - F32 z0 = last_outside.mV[VZ]; + const std::vector& vertices = edge.verticesUnderWater[lod]; + const LLVector4a& last_outside = vertices.back(); + F32 z0 = last_outside[VZ]; F32 z1 = outside_z; if ((z0 >= water_z && z1 >= water_z) || (z0 < water_z && z1 < water_z)) return; F32 part = (water_z - z0) / (z1 - z0); - const LLVector3& last_inside = edge.vertices[edge.vertices.size() - 2]; - split(last_inside, inside_x, inside_y, inside_z, part); - split(last_outside, outside_x, outside_y, outside_z, part); + const LLVector4a& last_inside = vertices[vertices.size() - 2]; + split(lod, last_inside, inside_x, inside_y, inside_z, part); + split(lod, last_outside, outside_x, outside_y, outside_z, part); }; - // First part, only one vertex - outside_z = land.resolveHeightRegion( outside_x, outside_y ); - - edge.vertices.emplace_back(outside_x, outside_y, outside_z); - - inside_x += dx * LINE_WIDTH; - inside_y += dy * LINE_WIDTH; - - outside_x += dx * LINE_WIDTH; - outside_y += dy * LINE_WIDTH; - - // Then the "actual edge" - inside_z = land.resolveHeightRegion( inside_x, inside_y ); - outside_z = land.resolveHeightRegion( outside_x, outside_y ); + auto pushTwoVertices = [&](U32 lod) + { + LLVector3 out(outside_x, outside_y, outside_z); + LLVector3 in(inside_x, inside_y, inside_z); + if (fabs(inside_z - outside_z) < LINE_WIDTH / 5) + { + edge.pushVertex(lod, inside_x, inside_y, inside_z, water_z); + } + else + { + // Make the line thinner if heights differ too much + LLVector3 dist(in - out); + F32 coef = dist.length() / LINE_WIDTH; + LLVector3 new_in(out + dist / coef); + edge.pushVertex(lod, new_in[VX], new_in[VY], new_in[VZ], water_z); + } + edge.pushVertex(lod, outside_x, outside_y, outside_z, water_z); + }; - edge.vertices.emplace_back(inside_x, inside_y, inside_z); - edge.vertices.emplace_back(outside_x, outside_y, outside_z); + // Point A simplified (first two vertices) + pushTwoVertices(1); - inside_x += dx * (dx - LINE_WIDTH); - inside_y += dy * (dy - LINE_WIDTH); + // Point A detailized (only one vertex) + edge.pushVertex(0, outside_x, outside_y, outside_z, water_z); - outside_x += dx * (dx - LINE_WIDTH); - outside_y += dy * (dy - LINE_WIDTH); + // Point B (two vertices) + move(LINE_WIDTH); + pushTwoVertices(0); - // Middle part, full width + // Points C, D, E + F32 distance = 1.f - LINE_WIDTH; constexpr S32 GRID_STEP = (S32)PARCEL_GRID_STEP_METERS; - for (S32 i = 1; i < GRID_STEP; i++) + for (U32 i = 1; i < GRID_STEP; ++i) { - inside_z = land.resolveHeightRegion( inside_x, inside_y ); - outside_z = land.resolveHeightRegion( outside_x, outside_y ); - - checkForSplit(); - - edge.vertices.emplace_back(inside_x, inside_y, inside_z); - edge.vertices.emplace_back(outside_x, outside_y, outside_z); - - inside_x += dx; - inside_y += dy; - - outside_x += dx; - outside_y += dy; + move(distance); + checkForSplit(0); + pushTwoVertices(0); + distance = 1.f; } - // Extra buffer for edge - inside_x -= dx * LINE_WIDTH; - inside_y -= dy * LINE_WIDTH; - - outside_x -= dx * LINE_WIDTH; - outside_y -= dy * LINE_WIDTH; + // Point F (two vertices) + move(1.f - LINE_WIDTH); + checkForSplit(0); + pushTwoVertices(0); - inside_z = land.resolveHeightRegion( inside_x, inside_y ); - outside_z = land.resolveHeightRegion( outside_x, outside_y ); + // Point G simplified (last two vertices) + move(LINE_WIDTH); + pushTwoVertices(1); - checkForSplit(); - - edge.vertices.emplace_back(inside_x, inside_y, inside_z); - edge.vertices.emplace_back(outside_x, outside_y, outside_z); - - outside_x += dx * LINE_WIDTH; - outside_y += dy * LINE_WIDTH; + // Point G detailized (only one vertex) + edge.pushVertex(0, outside_x, outside_y, outside_z, water_z); +} - // Last edge is not drawn to the edge - outside_z = land.resolveHeightRegion( outside_x, outside_y ); +void LLViewerParcelOverlay::Edge::pushVertex(U32 lod, F32 x, F32 y, F32 z, F32 water_z) +{ + verticesUnderWater[lod].emplace_back(x, y, z); + gGL.transform(verticesUnderWater[lod].back()); - edge.vertices.emplace_back(outside_x, outside_y, outside_z); + if (z >= water_z) + { + verticesAboveWater[lod].push_back(verticesUnderWater[lod].back()); + } + else + { + verticesAboveWater[lod].emplace_back(x, y, water_z); + gGL.transform(verticesAboveWater[lod].back()); + } } void LLViewerParcelOverlay::setDirty() @@ -665,6 +687,9 @@ void LLViewerParcelOverlay::renderPropertyLines() if (!show) return; + LL_PROFILE_ZONE_SCOPED; + LL_PROFILE_GPU_ZONE("Property Lines"); + LLSurface& land = mRegion->getLand(); bool render_water = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER); @@ -702,6 +727,8 @@ void LLViewerParcelOverlay::renderPropertyLines() // Stomp the camera into two dimensions LLVector3 camera_region = mRegion->getPosRegionFromGlobal( gAgentCamera.getCameraPositionGlobal() ); + bool draw_underwater = camera_region.mV[VZ] < water_z || + !gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER); // Set up a cull plane 2 * PARCEL_GRID_STEP_METERS behind // the camera. The cull plane normal is the camera's at axis. @@ -709,15 +736,23 @@ void LLViewerParcelOverlay::renderPropertyLines() cull_plane_point *= -2.f * PARCEL_GRID_STEP_METERS; cull_plane_point += camera_region; - bool render_hidden = LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build"); + bool render_hidden = !draw_underwater && + LLSelectMgr::sRenderHiddenSelections && + LLFloaterReg::instanceVisible("build"); constexpr F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f; + const F32 PROPERTY_LINE_LOD0_DIST_SQUARED = PROPERTY_LINE_CLIP_DIST_SQUARED / 25; for (const Edge& edge : mEdges) { - LLVector3 center = edge.vertices[edge.vertices.size() >> 1]; - - if (dist_vec_squared2D(center, camera_region) > PROPERTY_LINE_CLIP_DIST_SQUARED) + const std::vector& vertices0 = edge.verticesAboveWater[0]; + const F32* first = vertices0.front().getF32ptr(); + const F32* last = vertices0.back().getF32ptr(); + LLVector3 center((first[VX] + last[VX]) / 2, (first[VY] + last[VY]) / 2, (first[VZ] + last[VZ]) / 2); + gGL.untransform(center); + + F32 dist_squared = dist_vec_squared(center, camera_region); + if (dist_squared > PROPERTY_LINE_CLIP_DIST_SQUARED) { continue; } @@ -731,43 +766,33 @@ void LLViewerParcelOverlay::renderPropertyLines() continue; } + U32 lod = dist_squared < PROPERTY_LINE_LOD0_DIST_SQUARED ? 0 : 1; + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.color4ubv(edge.color.mV); - for (const LLVector3& vertex : edge.vertices) + if (draw_underwater) { - if (render_hidden || camera_z < water_z || vertex.mV[2] >= water_z) - { - gGL.vertex3fv(vertex.mV); - } - else - { - LLVector3 visible = vertex; - visible.mV[VZ] = water_z; - gGL.vertex3fv(visible.mV); - } + gGL.vertexBatchPreTransformed(edge.verticesUnderWater[lod]); } - - gGL.end(); - - if (render_hidden) + else { - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); + gGL.vertexBatchPreTransformed(edge.verticesAboveWater[lod]); - gGL.begin(LLRender::TRIANGLE_STRIP); + if (render_hidden) + { + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); - LLColor4U color = edge.color; - color.mV[VALPHA] /= 4; - gGL.color4ubv(color.mV); + LLColor4U color = edge.color; + color.mV[VALPHA] /= 4; + gGL.color4ubv(color.mV); - for (const LLVector3& vertex : edge.vertices) - { - gGL.vertex3fv(vertex.mV); + gGL.vertexBatchPreTransformed(edge.verticesUnderWater[lod]); } - - gGL.end(); } + + gGL.end(); } gGL.popMatrix(); diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h index 50bef02ddf7..7271c857013 100644 --- a/indra/newview/llviewerparceloverlay.h +++ b/indra/newview/llviewerparceloverlay.h @@ -116,7 +116,10 @@ class LLViewerParcelOverlay : public LLGLUpdate struct Edge { - std::vector vertices; + void pushVertex(U32 lod, F32 x, F32 y, F32 z, F32 water_z); + // LOD: 0 - detailized, 1 - simplified + std::vector verticesAboveWater[2]; + std::vector verticesUnderWater[2]; LLColor4U color; }; diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index f6ee00cb25c..d33d4267693 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -126,8 +126,6 @@ #include "llfloater.h" #include -#include -#include #include #include "glm/glm.hpp" diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index cd70f8f9b98..f31befd1ab4 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -104,7 +104,7 @@ S32 LLViewerRegion::sLastCameraUpdated = 0; S32 LLViewerRegion::sNewObjectCreationThrottle = -1; LLViewerRegion::vocache_entry_map_t LLViewerRegion::sRegionCacheCleanup; -typedef std::map CapabilityMap; +typedef std::unordered_map> CapabilityMap; static void log_capabilities(const CapabilityMap &capmap); @@ -3300,6 +3300,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("SetDisplayName"); capabilityNames.append("SimConsoleAsync"); capabilityNames.append("SimulatorFeatures"); + capabilityNames.append("SpatialVoiceModerationRequest"); capabilityNames.append("StartGroupProposal"); capabilityNames.append("TerrainNavMeshProperties"); capabilityNames.append("TextureStats"); @@ -3437,7 +3438,7 @@ void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::stri } } -std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const +std::string LLViewerRegion::getCapabilityDebug(std::string_view name) const { CapabilityMap::const_iterator iter = mImpl->mSecondCapabilitiesTracker.find(name); if (iter == mImpl->mSecondCapabilitiesTracker.end()) @@ -3448,15 +3449,14 @@ std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const return iter->second; } - -bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) +bool LLViewerRegion::isSpecialCapabilityName(std::string_view name) { return name == "EventQueueGet" || name == "UntrustedSimulatorMessage"; } -std::string LLViewerRegion::getCapability(const std::string& name) const +std::string LLViewerRegion::getCapability(std::string_view name) const { - if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) + if (!capabilitiesReceived() && (name != "Seed") && (name != "ObjectMedia")) { LL_WARNS() << "getCapability called before caps received for " << name << LL_ENDL; } @@ -3464,21 +3464,20 @@ std::string LLViewerRegion::getCapability(const std::string& name) const CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); if(iter == mImpl->mCapabilities.end()) { - return ""; + return {}; } return iter->second; } -bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const +bool LLViewerRegion::isCapabilityAvailable(std::string_view name) const { - if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) + if (!capabilitiesReceived() && (name != "Seed") && (name != "ObjectMedia")) { LL_WARNS() << "isCapabilityAvailable called before caps received for " << name << LL_ENDL; } - CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); - if(iter == mImpl->mCapabilities.end()) + if (!mImpl->mCapabilities.contains(name)) { return false; } @@ -3734,9 +3733,14 @@ bool LLViewerRegion::avatarHoverHeightEnabled() const void log_capabilities(const CapabilityMap &capmap) { + // Copy into sorted map for ordered output + using SortedCapabilityMap = std::map; + SortedCapabilityMap sorted_capmap; + sorted_capmap.insert(capmap.begin(), capmap.end()); + S32 count = 0; - CapabilityMap::const_iterator iter; - for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count) + SortedCapabilityMap::const_iterator iter; + for (iter = sorted_capmap.begin(); iter != sorted_capmap.end(); ++iter, ++count) { if (!iter->second.empty()) { @@ -3797,6 +3801,16 @@ std::string LLViewerRegion::getSimHostName() return std::string("..."); } + +bool LLViewerRegion::isRegionWebRTCEnabled() +{ + if (mSimulatorFeaturesReceived && mSimulatorFeatures.has("VoiceServerType")) + { + return mSimulatorFeatures["VoiceServerType"].asString() == "webrtc"; + } + return false; +} + void LLViewerRegion::applyCacheMiscExtras(LLViewerObject* obj) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index b3ec8579071..f1eb3355825 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -274,10 +274,10 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface S32 getNumSeedCapRetries(); void setCapability(const std::string& name, const std::string& url); void setCapabilityDebug(const std::string& name, const std::string& url); - bool isCapabilityAvailable(const std::string& name) const; + bool isCapabilityAvailable(std::string_view name) const; // implements LLCapabilityProvider - virtual std::string getCapability(const std::string& name) const; - std::string getCapabilityDebug(const std::string& name) const; + virtual std::string getCapability(std::string_view name) const; + std::string getCapabilityDebug(std::string_view name) const; // has region received its final (not seed) capability list? @@ -287,7 +287,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface void setCapabilitiesError(); boost::signals2::connection setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb); - static bool isSpecialCapabilityName(const std::string &name); + static bool isSpecialCapabilityName(std::string_view name); void logActiveCapabilities() const; // Utilities to post and get via @@ -424,6 +424,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface std::string getSimHostName(); + bool isRegionWebRTCEnabled(); + static bool isNewObjectCreationThrottleDisabled() {return sNewObjectCreationThrottle < 0;} // rebuild reflection probe list diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index d39d4662053..db6d83db5f4 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -263,6 +263,20 @@ LLTrace::SampleStatHandle > HUDS_FRAME_PCT("huds_ LLTrace::SampleStatHandle > UI_FRAME_PCT("ui_frame_pct"); LLTrace::SampleStatHandle > SWAP_FRAME_PCT("swap_frame_pct"); LLTrace::SampleStatHandle > IDLE_FRAME_PCT("idle_frame_pct"); + + + +LLTrace::SampleStatHandle WEBRTC_PACKETS_IN_LOST("webrtc_packets_in_lost", "Lost incoming packets"), + WEBRTC_PACKETS_IN_RECEIVED("webrtc_packets_in_recv", "Incoming packets received"), + WEBRTC_PACKETS_OUT_SENT("webrtc_packets_out_sent", "Outgoing packets sent"), + WEBRTC_PACKETS_OUT_LOST("webrtc_packets_out_lost", "Lost outgoing packets"); + +LLTrace::SampleStatHandle WEBRTC_JITTER_OUT("webrtc_jitter_out", "Timing variation of outgoing audio"), + WEBRTC_JITTER_IN("webrtc_jitter_in", "Timing variation of incoming audio"), + WEBRTC_LATENCY("webrtc_latency", "Round-trip audio delay"), + WEBRTC_UPLOAD_BANDWIDTH("webrtc_upload_bandwidth", "Estimated upload bandwidth"), + WEBRTC_JITTER_BUFFER("webrtc_jitter_buffer", "Average delay added to smooth incoming audio"); + } LLViewerStats::LLViewerStats() diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 1ac8b2f66b9..8ec0dd00247 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -232,6 +232,9 @@ extern LLTrace::EventStatHandle > OBJECT_CACHE_HIT extern LLTrace::SampleStatHandle NOTRMALIZED_FRAMETIME_JITTER_SESSION; extern LLTrace::SampleStatHandle NORMALIZED_FRAMTIME_JITTER_PERIOD; +extern LLTrace::SampleStatHandle WEBRTC_PACKETS_IN_LOST, WEBRTC_PACKETS_IN_RECEIVED, WEBRTC_PACKETS_OUT_SENT, WEBRTC_PACKETS_OUT_LOST; +extern LLTrace::SampleStatHandle WEBRTC_JITTER_OUT, WEBRTC_JITTER_IN, WEBRTC_LATENCY, WEBRTC_UPLOAD_BANDWIDTH, WEBRTC_JITTER_BUFFER; + } class LLViewerStats : public LLSingleton diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 1e834827528..0f23596c9a8 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1488,7 +1488,9 @@ bool LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/) // from local images, but this might become unsafe in case of changes to fetcher if (mBoostLevel == BOOST_PREVIEW) { - mRawImage->biasedScaleToPowerOfTwo(1024); + // A local file with a preview flag likely means mesh's texture upload + // which should follow normal upload scaling rules + mRawImage->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); } else { // leave black border, do not scale image content @@ -1896,12 +1898,10 @@ bool LLViewerFetchedTexture::processFetchResults(S32& desired_discard, S32 curre mRawDiscardLevel = INVALID_DISCARD_LEVEL; mIsFetching = false; mLastPacketTimer.reset(); + return false; } - else - { - mIsRawImageValid = true; - addToCreateTexture(); - } + + mIsRawImageValid = true; if (mBoostLevel == LLGLTexture::BOOST_ICON) { @@ -1914,7 +1914,11 @@ bool LLViewerFetchedTexture::processFetchResults(S32& desired_discard, S32 curre // // BOOST_ICON gets scaling because profile icons can have a bunch of different formats, not just j2c // Might need another pass to use discard for j2c and scaling for everything else. - mRawImage = mRawImage->scaled(expected_width, expected_height); + LLPointer scaled = mRawImage->scaled(expected_width, expected_height); + if (scaled.notNull()) + { + mRawImage = scaled; + } } } @@ -1929,10 +1933,16 @@ bool LLViewerFetchedTexture::processFetchResults(S32& desired_discard, S32 curre // // Todo: probably needs to be remade to use discard, all thumbnails are supposed to be j2c, // so no need to scale, should be posible to use discard to scale image down. - mRawImage = mRawImage->scaled(expected_width, expected_height); + LLPointer scaled = mRawImage->scaled(expected_width, expected_height); + if (scaled.notNull()) + { + mRawImage = scaled; + } } } + addToCreateTexture(); + return true; } else @@ -2574,14 +2584,31 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() S32 best_raw_discard = gl_discard; // Current GL quality level S32 current_aux_discard = MAX_DISCARD_LEVEL + 1; S32 best_aux_discard = MAX_DISCARD_LEVEL + 1; + LLImageRaw *current_raw_image = nullptr; if (mIsRawImageValid) { - // If we have an existing raw image, we have a baseline for the raw and auxiliary quality levels. + // If we have an existing raw image, we have a baseline for the raw + // and auxiliary quality levels. + // Note: we call updateImagesCreateTextures before callbacks, which + // leads to destroyRawImage and deletes raw image. So this case + // might be rare or even never trigger as there is never a raw image, + // only a saved one. current_raw_discard = mRawDiscardLevel; best_raw_discard = llmin(best_raw_discard, mRawDiscardLevel); best_aux_discard = llmin(best_aux_discard, mRawDiscardLevel); // We always decode the aux when we decode the base raw current_aux_discard = llmin(current_aux_discard, best_aux_discard); + current_raw_image = mRawImage; + } + else if (mSavedRawImage.notNull()) + { + // We have a saved raw image, we can use that as our baseline for + // raw and auxiliary quality levels. + current_raw_discard = mSavedRawDiscardLevel; + best_raw_discard = llmin(best_raw_discard, mSavedRawDiscardLevel); + best_aux_discard = llmin(best_aux_discard, mSavedRawDiscardLevel); // We always decode the aux when we decode the base raw + current_aux_discard = llmin(current_aux_discard, best_aux_discard); + current_raw_image = mSavedRawImage; } else { @@ -2646,12 +2673,17 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() if (need_readback) { readbackRawImage(); + if (mIsRawImageValid) + { + current_raw_discard = mRawDiscardLevel; + current_raw_image = mRawImage; + } } // // Run raw/auxiliary data callbacks // - if (run_raw_callbacks && mIsRawImageValid && (mRawDiscardLevel <= getMaxDiscardLevel())) + if (run_raw_callbacks && current_raw_image != nullptr && (current_raw_discard <= getMaxDiscardLevel())) { // Do callbacks which require raw image data. //LL_INFOS() << "doLoadedCallbacks raw for " << getID() << LL_ENDL; @@ -2662,7 +2694,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() { callback_list_t::iterator curiter = iter++; LLLoadedCallbackEntry *entryp = *curiter; - if (entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > mRawDiscardLevel)) + if (entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > current_raw_discard)) { // If we've loaded all the data there is to load or we've loaded enough // to satisfy the interested party, then this is the last time that @@ -2673,11 +2705,11 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() { LL_WARNS() << "Raw Image with no Aux Data for callback" << LL_ENDL; } - bool final = mRawDiscardLevel <= entryp->mDesiredDiscard; + bool final = current_raw_discard <= entryp->mDesiredDiscard; //LL_INFOS() << "Running callback for " << getID() << LL_ENDL; - //LL_INFOS() << mRawImage->getWidth() << "x" << mRawImage->getHeight() << LL_ENDL; - entryp->mLastUsedDiscard = mRawDiscardLevel; - entryp->mCallback(true, this, mRawImage, mAuxRawImage, mRawDiscardLevel, final, entryp->mUserData); + //LL_INFOS() << current_raw_image->getWidth() << "x" << current_raw_image->getHeight() << LL_ENDL; + entryp->mLastUsedDiscard = current_raw_discard; + entryp->mCallback(true, this, current_raw_image, mAuxRawImage, current_raw_discard, final, entryp->mUserData); if (final) { iter = mLoadedCallbackList.erase(curiter); diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 11ca3098fd2..96962bbeaeb 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1191,15 +1191,19 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time) LLTimer timer; image_list_t::iterator enditer = mFastCacheList.begin(); - for (image_list_t::iterator iter = mFastCacheList.begin(); - iter != mFastCacheList.end();) { - image_list_t::iterator curiter = iter++; - enditer = iter; - LLViewerFetchedTexture *imagep = *curiter; - imagep->loadFromFastCache(); - if (timer.getElapsedTimeF32() > max_time) - break; + // prelock fast cache mutex to avoid waiting multiple times. + LLMutexLock cache_lock(LLAppViewer::getTextureCache()->getFastCacheMutex()); + for (image_list_t::iterator iter = mFastCacheList.begin(); + iter != mFastCacheList.end();) + { + image_list_t::iterator curiter = iter++; + enditer = iter; + LLViewerFetchedTexture* imagep = *curiter; + imagep->loadFromFastCache(); + if (timer.getElapsedTimeF32() > max_time) + break; + } } mFastCacheList.erase(mFastCacheList.begin(), enditer); return timer.getElapsedTimeF32(); diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index 583fb253300..50af9756a39 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -96,6 +96,7 @@ LLViewerWearable::~LLViewerWearable() // virtual LLWearable::EImportResult LLViewerWearable::importStream( std::istream& input_stream, LLAvatarAppearance* avatarp ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; // suppress texlayerset updates while wearables are being imported. Layersets will be updated // when the wearables are "worn", not loaded. Note state will be restored when this object is destroyed. LLOverrideBakedTextureUpdate stop_bakes(false); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 187cfc97922..8695b969526 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include #include "llagent.h" @@ -1336,7 +1335,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi // Check the whitelist, if there's media (otherwise just show it) if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url)) { - if ( obj != mDragHoveredObject.get()) + if (obj != mDragHoveredObject) { // Highlight the dragged object LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); @@ -2076,10 +2075,6 @@ void LLViewerWindow::initGLDefaults() gBox.prerender(); } -struct MainPanel : public LLPanel -{ -}; - void LLViewerWindow::initBase() { S32 height = getWindowHeightScaled(); @@ -2118,6 +2113,8 @@ void LLViewerWindow::initBase() main_view->setShape(full_window); getRootView()->addChild(main_view); + mMainView = main_view; + // placeholder widget that controls where "world" is rendered mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle(); mPopupView = main_view->getChild("popup_holder"); @@ -3330,7 +3327,7 @@ void LLViewerWindow::clearPopups() void LLViewerWindow::moveCursorToCenter() { bool mouse_warp = false; - LLCachedControl mouse_warp_mode(gSavedSettings, "MouseWarpMode", 1); + static LLCachedControl mouse_warp_mode(gSavedSettings, "MouseWarpMode", 1); switch (mouse_warp_mode()) { @@ -3403,13 +3400,11 @@ void append_xui_tooltip(LLView* viewp, LLToolTip::Params& params) } } -static LLTrace::BlockTimerStatHandle ftm("Update UI"); - // Update UI based on stored mouse position from mouse-move // event processing. void LLViewerWindow::updateUI() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(ftm); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; static std::string last_handle_msg; @@ -3427,12 +3422,15 @@ void LLViewerWindow::updateUI() } } - LLConsole::updateClass(); + { + LL_PROFILE_ZONE_NAMED("UI updateClass"); + LLConsole::updateClass(); - // execute postponed arrange calls - LLAccordionCtrl::updateClass(); - // animate layout stacks so we have up to date rect for world view - LLLayoutStack::updateClass(); + // execute postponed arrange calls + LLAccordionCtrl::updateClass(); + // animate layout stacks so we have up to date rect for world view + LLLayoutStack::updateClass(); + } // use full window for world view when not rendering UI bool world_view_uses_full_window = gAgentCamera.cameraMouselook() || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI); @@ -3861,6 +3859,7 @@ void LLViewerWindow::updateUI() void LLViewerWindow::updateLayout() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; LLTool* tool = LLToolMgr::getInstance()->getCurrentTool(); if (gFloaterTools != NULL && tool != NULL @@ -4340,15 +4339,15 @@ void LLViewerWindow::pickAsync( S32 x, bool pick_unselectable, bool pick_reflection_probes) { + static LLCachedControl select_invisible_objects(gSavedSettings, "SelectInvisibleObjects"); // "Show Debug Alpha" means no object actually transparent bool in_build_mode = LLFloaterReg::instanceVisible("build"); - if (LLDrawPoolAlpha::sShowDebugAlpha - || (in_build_mode && gSavedSettings.getBOOL("SelectInvisibleObjects"))) + if (LLDrawPoolAlpha::sShowDebugAlpha || (in_build_mode && select_invisible_objects)) { pick_transparent = true; } - LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, pick_rigged, false, pick_reflection_probes, pick_unselectable, true, callback); + LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, pick_rigged, false, pick_reflection_probes, true, pick_unselectable, callback); schedulePick(pick_info); } @@ -4372,7 +4371,6 @@ void LLViewerWindow::schedulePick(LLPickInfo& pick_info) mWindow->delayInputProcessing(); } - void LLViewerWindow::performPick() { if (!mPicks.empty()) @@ -4406,8 +4404,9 @@ void LLViewerWindow::returnEmptyPicks() // Performs the GL object/land pick. LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, bool pick_transparent, bool pick_rigged, bool pick_particle, bool pick_unselectable, bool pick_reflection_probe) { + static LLCachedControl select_invisible_objects(gSavedSettings, "SelectInvisibleObjects"); bool in_build_mode = LLFloaterReg::instanceVisible("build"); - if ((in_build_mode && gSavedSettings.getBOOL("SelectInvisibleObjects")) || LLDrawPoolAlpha::sShowDebugAlpha) + if ((in_build_mode && select_invisible_objects) || LLDrawPoolAlpha::sShowDebugAlpha) { // build mode allows interaction with all transparent objects // "Show Debug Alpha" means no object actually transparent @@ -4415,7 +4414,7 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, bool pick_transp } // shortcut queueing in mPicks and just update mLastPick in place - MASK key_mask = gKeyboard->currentMask(true); + MASK key_mask = gKeyboard->currentMask(true); mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, pick_rigged, pick_particle, pick_reflection_probe, true, false, NULL); mLastPick.fetchResults(); @@ -4919,6 +4918,19 @@ void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_save if (image->save(filepath)) { playSnapshotAnimAndSound(); + + // Show clickable notification with filepath + LLSD args; + args["FILEPATH"] = filepath; + + LLSD payload; + payload["filepath"] = filepath; + + LLNotificationsUtil::add("SnapshotSavedToComputer", + args, + payload.with("respond_on_mousedown", true), + boost::bind(&LLViewerWindow::onSnapshotNotificationClick, _1, _2)); + success_cb(); } else @@ -4932,6 +4944,16 @@ void LLViewerWindow::resetSnapshotLoc() gSavedPerAccountSettings.setString("SnapshotBaseDir", std::string()); } +// static +void LLViewerWindow::onSnapshotNotificationClick(const LLSD& notification, const LLSD& response) +{ + std::string filepath = notification["payload"]["filepath"].asString(); + if (!filepath.empty()) + { + gDirUtilp->openDir(filepath); + } +} + // static void LLViewerWindow::movieSize(S32 new_width, S32 new_height) { @@ -6154,14 +6176,14 @@ LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos, bool pick_rigged, bool pick_particle, bool pick_reflection_probe, - bool pick_uv_coords, + bool pick_surface_info, bool pick_unselectable, void (*pick_callback)(const LLPickInfo& pick_info)) : mMousePt(mouse_pos), mKeyMask(keyboard_mask), mPickCallback(pick_callback), mPickType(PICK_INVALID), - mWantSurfaceInfo(pick_uv_coords), + mWantSurfaceInfo(pick_surface_info), mObjectFace(-1), mUVCoords(-1.f, -1.f), mSTCoords(-1.f, -1.f), diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index f3c7ef32898..ec28a3fc4aa 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -144,6 +144,10 @@ class LLPickInfo }; +struct MainPanel : public LLPanel +{ +}; + static const U32 MAX_SNAPSHOT_IMAGE_SIZE = 7680; // max snapshot image size 7680 * 7680 UHDTV2 class LLViewerWindow : public LLWindowCallbacks @@ -248,6 +252,7 @@ class LLViewerWindow : public LLWindowCallbacks // ACCESSORS // LLRootView* getRootView() const; + MainPanel* getMainView() const { return mMainView; } // 3D world area in scaled pixels (via UI scale), use for most UI computations LLRect getWorldViewRectScaled() const; @@ -405,6 +410,7 @@ class LLViewerWindow : public LLWindowCallbacks void resetSnapshotLoc(); void playSnapshotAnimAndSound(); + static void onSnapshotNotificationClick(const LLSD& notification, const LLSD& response); // draws selection boxes around selected objects, must call displayObjects first void renderSelections( bool for_gl_pick, bool pick_parcel_walls, bool for_hud ); @@ -501,6 +507,7 @@ class LLViewerWindow : public LLWindowCallbacks LLRect mWorldViewRectRaw; // area of screen for 3D world LLRect mWorldViewRectScaled; // area of screen for 3D world scaled by UI size LLRootView* mRootView; // a view of size mWindowRectRaw, containing all child views + MainPanel* mMainView; // a view of size mWindowRectRaw, directly containing the base elements of the ui tree LLView* mFloaterSnapRegion = nullptr; LLView* mNavBarContainer = nullptr; LLPanel* mStatusBarContainer = nullptr; diff --git a/indra/newview/llvlmanager.cpp b/indra/newview/llvlmanager.cpp index c2bcd32921c..f4c2c27cee2 100644 --- a/indra/newview/llvlmanager.cpp +++ b/indra/newview/llvlmanager.cpp @@ -68,7 +68,11 @@ void LLVLManager::addLayerData(LLVLData *vl_datap, const S32Bytes mesg_size) } else { - LL_ERRS() << "Unknown layer type!" << (S32)vl_datap->mType << LL_ENDL; + // Corrupted message? New feature? + LL_WARNS() << "Unknown layer type!" << (S32)vl_datap->mType + << " for region " << vl_datap->mRegionp->getName() << LL_ENDL; + delete vl_datap; // addLayerData took ownership + return; } mPacketData.push_back(vl_datap); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 438f84d6255..efb09479e20 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -217,6 +217,13 @@ enum ERenderName RENDER_NAME_FADE }; +enum ERenderGroupTitle +{ + RENDER_GROUP_TITLE_NEVER, + RENDER_GROUP_TITLE_SELF, + RENDER_GROUP_TITLE_ALWAYS +}; + #define JELLYDOLLS_SHOULD_IMPOSTOR //----------------------------------------------------------------------------- @@ -607,7 +614,7 @@ const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] = }; S32 LLVOAvatar::sRenderName = RENDER_NAME_ALWAYS; -bool LLVOAvatar::sRenderGroupTitles = true; +S32 LLVOAvatar::sRenderGroupTitles = RENDER_GROUP_TITLE_ALWAYS; S32 LLVOAvatar::sNumVisibleChatBubbles = 0; bool LLVOAvatar::sDebugInvisible = false; bool LLVOAvatar::sShowAttachmentPoints = false; @@ -3552,9 +3559,10 @@ void LLVOAvatar::idleUpdateNameTagText(bool new_name) addNameTagLine(line, name_tag_color, LLFontGL::NORMAL, LLFontGL::getFontSansSerifSmall()); } + bool render_title = (sRenderGroupTitles == RENDER_GROUP_TITLE_ALWAYS) || + (isSelf() && (sRenderGroupTitles == RENDER_GROUP_TITLE_SELF)); - if (sRenderGroupTitles - && title && title->getString() && title->getString()[0] != '\0') + if (render_title && title && title->getString() && title->getString()[0] != '\0') { std::string title_str = title->getString(); LLStringFn::replace_ascii_controlchars(title_str,LL_UNKNOWN_CHAR); @@ -11417,12 +11425,17 @@ void LLVOAvatar::calculateUpdateRenderComplexity() LLPerfStats::tunables.userFPSTuningStrategy != LLPerfStats::TUNE_SCENE_ONLY && !isVisuallyMuted()) { - LLUUID id = getID(); // <== use id to make sure this avatar didn't get deleted between frames - LL::WorkQueue::getInstance("mainloop")->post([this, id]() + const LLUUID id = getID(); // <== use id to make sure this avatar didn't get deleted between frames + LL::WorkQueue::getInstance("mainloop")->post([id]() { - if (gObjectList.findObject(id) != nullptr) + LLViewerObject* obj = gObjectList.findObject(id); + if (obj + && !obj->isDead() + && obj->isAvatar() + && obj->mDrawable) { - gPipeline.profileAvatar(this); + LLVOAvatar* avatar = (LLVOAvatar*)obj; + gPipeline.profileAvatar(avatar); } }); } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 1e563c48694..fc3a97a25d0 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -354,7 +354,7 @@ class LLVOAvatar : //-------------------------------------------------------------------- public: static S32 sRenderName; - static bool sRenderGroupTitles; + static S32 sRenderGroupTitles; static const U32 NON_IMPOSTORS_MAX_SLIDER; /* Must equal the maximum allowed the RenderAvatarMaxNonImpostors * slider in panel_preferences_graphics1.xml */ static U32 sMaxNonImpostors; // affected by control "RenderAvatarMaxNonImpostors" @@ -1120,7 +1120,7 @@ class LLVOAvatar : bool mNameFriend; bool mNameCloud; F32 mNameAlpha; - bool mRenderGroupTitles; + S32 mRenderGroupTitles; //-------------------------------------------------------------------- // Display the name (then optionally fade it out) diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 71a9e71a9fd..ccaefebf509 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -39,6 +39,7 @@ #include "llagent.h" #include "lltrans.h" #include "lluiusage.h" +#include "llnearbyvoicemoderation.h" const F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f; @@ -668,6 +669,9 @@ void LLVoiceClient::setUserPTTState(bool ptt) { if (ptt) { + // Nearby chat is muted by moderator, don't toggle PTT + if (!mUserPTTState && LLNearbyVoiceModeration::getInstance()->showNotificationIfNeeded()) + return; LLUIUsage::instance().logCommand("Agent.EnableMicrophone"); } mUserPTTState = ptt; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index d132cbfa36d..107a08fdf8b 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -1107,7 +1107,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() while (!sPump && !sShuttingDown) { // Can't use the pump until we have it available. - llcoro::suspend(); + llcoro::suspendUntilNextFrame(); } if (sShuttingDown) diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 80a0e3e5c0e..2a0fdbfac16 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -61,10 +61,12 @@ #include "llrand.h" #include "llviewerwindow.h" #include "llviewercamera.h" +#include "llviewerstats.h" #include "llversioninfo.h" #include "llviewernetwork.h" #include "llnotificationsutil.h" +#include "llnearbyvoicemoderation.h" #include "llcorehttputil.h" #include "lleventfilter.h" @@ -80,6 +82,8 @@ const std::string WEBRTC_VOICE_SERVER_TYPE = "webrtc"; +const F32 STATS_TIMER_DELAY = 2.0; + namespace { const F32 MAX_AUDIO_DIST = 50.0f; @@ -2496,17 +2500,18 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro(connectionPtr_t connection) // callback from llwebrtc void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp) { + connectionPtr_t connection = shared_from_this(); LL::WorkQueue::postMaybe(mMainQueue, - [=, this] { - if (mShutDown) + [=] { + if (connection->mShutDown) { return; } LL_DEBUGS("Voice") << "On Offer Available." << LL_ENDL; - mChannelSDP = sdp; - if (mVoiceConnectionState == VOICE_STATE_WAIT_FOR_SESSION_START) + connection->mChannelSDP = sdp; + if (connection->mVoiceConnectionState == VOICE_STATE_WAIT_FOR_SESSION_START) { - mVoiceConnectionState = VOICE_STATE_REQUEST_CONNECTION; + connection->mVoiceConnectionState = VOICE_STATE_REQUEST_CONNECTION; } }); } @@ -2523,16 +2528,17 @@ void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp) // callback from llwebrtc void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface* audio_interface) { + connectionPtr_t connection = shared_from_this(); LL::WorkQueue::postMaybe(mMainQueue, - [=, this] { - if (mShutDown) + [=] { + if (connection->mShutDown) { return; } LL_DEBUGS("Voice") << "On AudioEstablished." << LL_ENDL; - mWebRTCAudioInterface = audio_interface; - mWebRTCAudioInterface->setMute(true); // mute will be set appropriately later when we finish setting up. - setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED); + connection->mWebRTCAudioInterface = audio_interface; + connection->mWebRTCAudioInterface->setMute(true); // mute will be set appropriately later when we finish setting up. + connection->setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED); }); } @@ -2902,6 +2908,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() } mWebRTCAudioInterface->setReceiveVolume(mSpeakerVolume); LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID, mRegionID); + resetConnectionStats(); setVoiceConnectionState(VOICE_STATE_WAIT_FOR_DATA_CHANNEL); break; } @@ -2955,6 +2962,13 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() sendJoin(); } } + + static LLTimer stats_timer; + if (stats_timer.getElapsedTimeF32() > STATS_TIMER_DELAY) + { + mWebRTCPeerConnectionInterface->gatherConnectionStats(); + stats_timer.reset(); + } } break; } @@ -3171,12 +3185,54 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b if (participant_obj.contains("m") && participant_obj["m"].is_bool()) { - participant->mIsModeratorMuted = participant_obj["m"].as_bool(); + bool is_moderator_muted = participant_obj["m"].as_bool(); + if (isSpatial()) + { + // ignore muted flags from non-primary server + if (mPrimary || primary) + { + participant->mIsModeratorMuted = is_moderator_muted; + if (gAgentID == agent_id) + { + LLNearbyVoiceModeration::getInstance()->setMutedInfo(mChannelID, is_moderator_muted); + } + } + } + else + { + participant->mIsModeratorMuted = is_moderator_muted; + } + } + } + } + else + { + if (isSpatial() && (mPrimary || primary)) + { + // mute info message can be received before join message, so try to mute again later + if (participant_obj.contains("m") && participant_obj["m"].is_bool()) + { + bool is_moderator_muted = participant_obj["m"].as_bool(); + std::string channel_id = mChannelID; + F32 delay { 1.5f }; + doAfterInterval( + [channel_id, agent_id, is_moderator_muted]() + { + LLWebRTCVoiceClient::participantStatePtr_t participant = + LLWebRTCVoiceClient::getInstance()->findParticipantByID(channel_id, agent_id); + if (participant) + { + participant->mIsModeratorMuted = is_moderator_muted; + if (gAgentID == agent_id) + { + LLNearbyVoiceModeration::getInstance()->setMutedInfo(channel_id, is_moderator_muted); + } + } + }, delay); } } } } - // tell the simulator to set the mute and volume data for this // participant, if there are any updates. boost::json::object root; @@ -3207,17 +3263,18 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b // llwebrtc callback void LLVoiceWebRTCConnection::OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface) { + connectionPtr_t connection = shared_from_this(); LL::WorkQueue::postMaybe(mMainQueue, - [=, this] { - if (mShutDown) + [=] { + if (connection->mShutDown) { return; } if (data_interface) { - mWebRTCDataInterface = data_interface; - mWebRTCDataInterface->setDataObserver(this); + connection->mWebRTCDataInterface = data_interface; + connection->mWebRTCDataInterface->setDataObserver(connection.get()); } }); } @@ -3247,6 +3304,112 @@ void LLVoiceWebRTCConnection::sendJoin() mWebRTCDataInterface->sendData(json_data, false); } +void LLVoiceWebRTCConnection::OnStatsDelivered(const llwebrtc::LLWebRTCStatsMap& stats_data) +{ + LL::WorkQueue::postMaybe(mMainQueue, [=, this] + { + if (mShutDown) + { + return; + } + for (const auto& [stats_id, attributes] : stats_data) + { + if (attributes.contains("currentRoundTripTime")) + { + F32 rtt_seconds = 0.0f; + LLStringUtil::convertToF32(attributes.at("currentRoundTripTime"), rtt_seconds); + sample(LLStatViewer::WEBRTC_LATENCY, rtt_seconds * 1000.0f); + } + if (attributes.contains("availableOutgoingBitrate")) + { + F32 bitrate_bps = 0.0f; + LLStringUtil::convertToF32(attributes.at("availableOutgoingBitrate"), bitrate_bps); + sample(LLStatViewer::WEBRTC_UPLOAD_BANDWIDTH, bitrate_bps / 1000.0f); + } + + // Stat type detection below is heuristic-based. + // It's relied on specific fields to distinguish outbound-rtp, remote-inbound-rtp, and inbound-rtp. + // This approach works with current WebRTC stats but may need updating later. + + // Outbound RTP + if (attributes.contains("mediaSourceId")) + { + U32 out_packets_sent = 0; + LLStringUtil::convertToU32(attributes.at("packetsSent"), out_packets_sent); + sample(LLStatViewer::WEBRTC_PACKETS_OUT_SENT, out_packets_sent); + } + // Remote-Inbound RTP + else if (attributes.contains("localId")) + { + if (attributes.contains("packetsLost")) + { + U32 out_packets_lost = 0; + LLStringUtil::convertToU32(attributes.at("packetsLost"), out_packets_lost); + sample(LLStatViewer::WEBRTC_PACKETS_OUT_LOST, out_packets_lost); + } + if (attributes.contains("jitter")) + { + F32 jitter_seconds = 0.0f; + LLStringUtil::convertToF32(attributes.at("jitter"), jitter_seconds); + sample(LLStatViewer::WEBRTC_JITTER_OUT, jitter_seconds * 1000.0f); + } + } + // Inbound RTP + else if (attributes.contains("jitterBufferDelay")) + { + if (attributes.contains("packetsLost")) + { + U32 in_packets_lost = 0; + LLStringUtil::convertToU32(attributes.at("packetsLost"), in_packets_lost); + sample(LLStatViewer::WEBRTC_PACKETS_IN_LOST, in_packets_lost); + } + if (attributes.contains("packetsReceived")) + { + U32 in_packets_recv = 0; + LLStringUtil::convertToU32(attributes.at("packetsReceived"), in_packets_recv); + sample(LLStatViewer::WEBRTC_PACKETS_IN_RECEIVED, in_packets_recv); + } + if (attributes.contains("jitter")) + { + F32 jitter_seconds = 0.0f; + LLStringUtil::convertToF32(attributes.at("jitter"), jitter_seconds); + sample(LLStatViewer::WEBRTC_JITTER_IN, jitter_seconds * 1000.0f); + } + if (attributes.contains("jitterBufferDelay") && attributes.contains("jitterBufferEmittedCount")) + { + F32 total_delay_seconds = 0.0f; + F32 emitted_count_f = 0.0f; + + // total delay in seconds + LLStringUtil::convertToF32(attributes.at("jitterBufferDelay"), total_delay_seconds); + + // number of packets played out + LLStringUtil::convertToF32(attributes.at("jitterBufferEmittedCount"), emitted_count_f); + if (emitted_count_f > 0.0f) + { + F32 avg_delay_seconds = total_delay_seconds / emitted_count_f; + F32 avg_delay_ms = avg_delay_seconds * 1000.0f; + sample(LLStatViewer::WEBRTC_JITTER_BUFFER, avg_delay_seconds * 1000.0f); + } + } + } + } + }); +} + +void LLVoiceWebRTCConnection::resetConnectionStats() +{ + sample(LLStatViewer::WEBRTC_JITTER_BUFFER, 0); + sample(LLStatViewer::WEBRTC_JITTER_IN, 0); + sample(LLStatViewer::WEBRTC_JITTER_OUT, 0); + sample(LLStatViewer::WEBRTC_LATENCY, 0); + sample(LLStatViewer::WEBRTC_PACKETS_IN_LOST, 0); + sample(LLStatViewer::WEBRTC_PACKETS_IN_RECEIVED, 0); + sample(LLStatViewer::WEBRTC_PACKETS_OUT_SENT, 0); + sample(LLStatViewer::WEBRTC_PACKETS_OUT_LOST, 0); + sample(LLStatViewer::WEBRTC_UPLOAD_BANDWIDTH, 0); +} + ///////////////////////////// // WebRTC Spatial Connection diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h index 2ce575852ab..6786b049c2d 100644 --- a/indra/newview/llvoicewebrtc.h +++ b/indra/newview/llvoicewebrtc.h @@ -540,6 +540,8 @@ class LLWebRTCVoiceClient : public LLSingleton, static bool sShuttingDown; LLEventMailDrop mWebRTCPump; + + LLSD mLastWebRTCStats; }; @@ -603,6 +605,8 @@ class LLVoiceWebRTCConnection : //@{ void OnDataReceived(const std::string &data, bool binary) override; void OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface) override; + + void OnStatsDelivered(const llwebrtc::LLWebRTCStatsMap& stats_data) override; //@} void OnDataReceivedImpl(const std::string &data, bool binary); @@ -638,6 +642,8 @@ class LLVoiceWebRTCConnection : void OnVoiceConnectionRequestSuccess(const LLSD &body); + void resetConnectionStats(); + protected: typedef enum e_voice_connection_state { diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 9c0f4baf28b..b328d3a414c 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -250,10 +250,12 @@ LLVOVolume::~LLVOVolume() delete mVolumeImpl; mVolumeImpl = NULL; - gMeshRepo.unregisterMesh(this); + unregisterOldMeshAndSkin(); if(!mMediaImplList.empty()) { + LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("delete volume media list"); + for(U32 i = 0 ; i < mMediaImplList.size() ; i++) { if(mMediaImplList[i].notNull()) @@ -351,7 +353,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, U8 sculpt_type = 0; if (isSculpted()) { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams *sculpt_params = getSculptParams(); if (sculpt_params) { sculpt_id = sculpt_params->getSculptTexture(); @@ -924,7 +926,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) if (getLightTextureID().notNull()) { - LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + LLLightImageParams* params = getLightImageParams(); LLUUID id = params->getLightTexture(); mLightTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE); if (mLightTexture.notNull()) @@ -1048,6 +1050,28 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) return mDrawable; } +// Inverse of gMeshRepo.loadMesh and gMeshRepo.getSkinInfo, combined into one function +// Assume a Collada mesh never changes after being set. +void LLVOVolume::unregisterOldMeshAndSkin() +{ + if (mVolumep) + { + const LLVolumeParams& params = mVolumep->getParams(); + if ((params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + { + // object is being deleted, so it will no longer need to request + // meshes. + for (S32 lod = 0; lod != LLVolumeLODGroup::NUM_LODS; ++lod) + { + gMeshRepo.unregisterMesh(this, params, lod); + } + // This volume may or may not have a skin + gMeshRepo.unregisterSkinInfo(params.getSculptID(), this); + } + } +} + + bool LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bool unique_volume) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; @@ -1082,7 +1106,7 @@ bool LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, true, false); if (!mVolumeImpl) { - LLFlexibleObjectData* data = (LLFlexibleObjectData*)getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + LLFlexibleObjectData* data = getFlexibleObjectData(); mVolumeImpl = new LLVolumeImplFlexible(this, data); } } @@ -1193,7 +1217,7 @@ void LLVOVolume::updateSculptTexture() if (isSculpted() && !isMesh()) { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams *sculpt_params = getSculptParams(); if (sculpt_params) { LLUUID id = sculpt_params->getSculptTexture(); @@ -3053,7 +3077,7 @@ void LLVOVolume::setLightTextureID(LLUUID id) { old_texturep->removeVolume(LLRender::LIGHT_TEX, this); } - LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + LLLightImageParams* param_block = getLightImageParams(); if (param_block && param_block->getLightTexture() != id) { param_block->setLightTexture(id); @@ -3083,7 +3107,7 @@ void LLVOVolume::setLightTextureID(LLUUID id) void LLVOVolume::setSpotLightParams(LLVector3 params) { - LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + LLLightImageParams* param_block = getLightImageParams(); if (param_block && param_block->getParams() != params) { param_block->setParams(params); @@ -3125,7 +3149,7 @@ void LLVOVolume::setLightSRGBColor(const LLColor3& color) void LLVOVolume::setLightLinearColor(const LLColor3& color) { - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + LLLightParams *param_block = getLightParams(); if (param_block) { if (param_block->getLinearColor() != color) @@ -3140,7 +3164,7 @@ void LLVOVolume::setLightLinearColor(const LLColor3& color) void LLVOVolume::setLightIntensity(F32 intensity) { - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + LLLightParams *param_block = getLightParams(); if (param_block) { if (param_block->getLinearColor().mV[3] != intensity) @@ -3153,7 +3177,7 @@ void LLVOVolume::setLightIntensity(F32 intensity) void LLVOVolume::setLightRadius(F32 radius) { - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + LLLightParams *param_block = getLightParams(); if (param_block) { if (param_block->getRadius() != radius) @@ -3166,7 +3190,7 @@ void LLVOVolume::setLightRadius(F32 radius) void LLVOVolume::setLightFalloff(F32 falloff) { - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + LLLightParams *param_block = getLightParams(); if (param_block) { if (param_block->getFalloff() != falloff) @@ -3179,7 +3203,7 @@ void LLVOVolume::setLightFalloff(F32 falloff) void LLVOVolume::setLightCutoff(F32 cutoff) { - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + LLLightParams *param_block = getLightParams(); if (param_block) { if (param_block->getCutoff() != cutoff) @@ -3194,7 +3218,7 @@ void LLVOVolume::setLightCutoff(F32 cutoff) bool LLVOVolume::getIsLight() const { - mIsLight = getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT); + mIsLight = getLightParams() != nullptr; return mIsLight; } @@ -3210,7 +3234,7 @@ LLColor3 LLVOVolume::getLightSRGBBaseColor() const LLColor3 LLVOVolume::getLightLinearBaseColor() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return LLColor3(param_block->getLinearColor()); @@ -3223,7 +3247,7 @@ LLColor3 LLVOVolume::getLightLinearBaseColor() const LLColor3 LLVOVolume::getLightLinearColor() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return LLColor3(param_block->getLinearColor()) * param_block->getLinearColor().mV[3]; @@ -3241,33 +3265,27 @@ LLColor3 LLVOVolume::getLightSRGBColor() const return ret; } -LLUUID LLVOVolume::getLightTextureID() const +const LLUUID& LLVOVolume::getLightTextureID() const { - if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) + const LLLightImageParams *param_block = getLightImageParams(); + if (param_block) { - const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); - if (param_block) - { - return param_block->getLightTexture(); - } + return param_block->getLightTexture(); } return LLUUID::null; } -LLVector3 LLVOVolume::getSpotLightParams() const +const LLVector3& LLVOVolume::getSpotLightParams() const { - if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) + const LLLightImageParams *param_block = getLightImageParams(); + if (param_block) { - const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); - if (param_block) - { - return param_block->getParams(); - } + return param_block->getParams(); } - return LLVector3(); + return LLVector3::zero; } F32 LLVOVolume::getSpotLightPriority() const @@ -3304,8 +3322,8 @@ void LLVOVolume::updateSpotLightPriority() bool LLVOVolume::isLightSpotlight() const { - LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); - if (params && getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) + const LLLightImageParams* params = getLightImageParams(); + if (params) { return params->isLightSpotlight(); } @@ -3315,7 +3333,7 @@ bool LLVOVolume::isLightSpotlight() const LLViewerTexture* LLVOVolume::getLightTexture() { - LLUUID id = getLightTextureID(); + const LLUUID& id = getLightTextureID(); if (id.notNull()) { @@ -3326,7 +3344,7 @@ LLViewerTexture* LLVOVolume::getLightTexture() } else { - mLightTexture = NULL; + mLightTexture = nullptr; } return mLightTexture; @@ -3334,7 +3352,7 @@ LLViewerTexture* LLVOVolume::getLightTexture() F32 LLVOVolume::getLightIntensity() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return param_block->getLinearColor().mV[3]; @@ -3347,7 +3365,7 @@ F32 LLVOVolume::getLightIntensity() const F32 LLVOVolume::getLightRadius() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return param_block->getRadius(); @@ -3360,7 +3378,7 @@ F32 LLVOVolume::getLightRadius() const F32 LLVOVolume::getLightFalloff(const F32 fudge_factor) const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return param_block->getFalloff() * fudge_factor; @@ -3373,7 +3391,7 @@ F32 LLVOVolume::getLightFalloff(const F32 fudge_factor) const F32 LLVOVolume::getLightCutoff() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return param_block->getCutoff(); @@ -3386,7 +3404,7 @@ F32 LLVOVolume::getLightCutoff() const bool LLVOVolume::isReflectionProbe() const { - return getParameterEntryInUse(LLNetworkData::PARAMS_REFLECTION_PROBE); + return getReflectionProbeParams() != nullptr; } bool LLVOVolume::setIsReflectionProbe(bool is_probe) @@ -3411,7 +3429,7 @@ bool LLVOVolume::setIsReflectionProbe(bool is_probe) bool LLVOVolume::setReflectionProbeAmbiance(F32 ambiance) { - LLReflectionProbeParams* param_block = (LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + LLReflectionProbeParams* param_block = getReflectionProbeParams(); if (param_block) { if (param_block->getAmbiance() != ambiance) @@ -3427,7 +3445,7 @@ bool LLVOVolume::setReflectionProbeAmbiance(F32 ambiance) bool LLVOVolume::setReflectionProbeNearClip(F32 near_clip) { - LLReflectionProbeParams* param_block = (LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + LLReflectionProbeParams* param_block = getReflectionProbeParams(); if (param_block) { if (param_block->getClipDistance() != near_clip) @@ -3443,7 +3461,7 @@ bool LLVOVolume::setReflectionProbeNearClip(F32 near_clip) bool LLVOVolume::setReflectionProbeIsBox(bool is_box) { - LLReflectionProbeParams* param_block = (LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + LLReflectionProbeParams* param_block = getReflectionProbeParams(); if (param_block) { if (param_block->getIsBox() != is_box) @@ -3459,7 +3477,7 @@ bool LLVOVolume::setReflectionProbeIsBox(bool is_box) bool LLVOVolume::setReflectionProbeIsDynamic(bool is_dynamic) { - LLReflectionProbeParams* param_block = (LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + LLReflectionProbeParams* param_block = getReflectionProbeParams(); if (param_block) { if (param_block->getIsDynamic() != is_dynamic) @@ -3475,7 +3493,7 @@ bool LLVOVolume::setReflectionProbeIsDynamic(bool is_dynamic) bool LLVOVolume::setReflectionProbeIsMirror(bool is_mirror) { - LLReflectionProbeParams *param_block = (LLReflectionProbeParams *) getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + LLReflectionProbeParams* param_block = getReflectionProbeParams(); if (param_block) { if (param_block->getIsMirror() != is_mirror) @@ -3498,7 +3516,7 @@ bool LLVOVolume::setReflectionProbeIsMirror(bool is_mirror) F32 LLVOVolume::getReflectionProbeAmbiance() const { - const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + const LLReflectionProbeParams* param_block = getReflectionProbeParams(); if (param_block) { return param_block->getAmbiance(); @@ -3511,7 +3529,7 @@ F32 LLVOVolume::getReflectionProbeAmbiance() const F32 LLVOVolume::getReflectionProbeNearClip() const { - const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + const LLReflectionProbeParams* param_block = getReflectionProbeParams(); if (param_block) { return param_block->getClipDistance(); @@ -3524,7 +3542,7 @@ F32 LLVOVolume::getReflectionProbeNearClip() const bool LLVOVolume::getReflectionProbeIsBox() const { - const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + const LLReflectionProbeParams* param_block = getReflectionProbeParams(); if (param_block) { return param_block->getIsBox(); @@ -3535,7 +3553,7 @@ bool LLVOVolume::getReflectionProbeIsBox() const bool LLVOVolume::getReflectionProbeIsDynamic() const { - const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + const LLReflectionProbeParams* param_block = getReflectionProbeParams(); if (param_block) { return param_block->getIsDynamic(); @@ -3546,8 +3564,7 @@ bool LLVOVolume::getReflectionProbeIsDynamic() const bool LLVOVolume::getReflectionProbeIsMirror() const { - const LLReflectionProbeParams *param_block = - (const LLReflectionProbeParams *) getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + const LLReflectionProbeParams* param_block = getReflectionProbeParams(); if (param_block) { return param_block->getIsMirror(); @@ -3568,7 +3585,7 @@ U32 LLVOVolume::getVolumeInterfaceID() const bool LLVOVolume::isFlexible() const { - if (getParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE)) + if (getFlexibleObjectData()) { LLVolume* volume = getVolume(); if (volume && volume->getParams().getPathParams().getCurveType() != LL_PCODE_PATH_FLEXIBLE) @@ -3587,7 +3604,7 @@ bool LLVOVolume::isFlexible() const bool LLVOVolume::isSculpted() const { - if (getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) + if (getSculptParams()) { return true; } @@ -3599,7 +3616,7 @@ bool LLVOVolume::isMesh() const { if (isSculpted()) { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = getSculptParams(); if (sculpt_params) { U8 sculpt_type = sculpt_params->getSculptType(); @@ -3617,7 +3634,7 @@ bool LLVOVolume::isMesh() const bool LLVOVolume::hasLightTexture() const { - if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) + if (getLightImageParams()) { return true; } @@ -3737,8 +3754,7 @@ bool LLVOVolume::isRiggedMesh() const //---------------------------------------------------------------------------- U32 LLVOVolume::getExtendedMeshFlags() const { - const LLExtendedMeshParams *param_block = - (const LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH); + const LLExtendedMeshParams *param_block = getExtendedMeshParams(); if (param_block) { return param_block->getFlags(); @@ -3783,8 +3799,7 @@ void LLVOVolume::setExtendedMeshFlags(U32 flags) { bool in_use = true; setParameterEntryInUse(LLNetworkData::PARAMS_EXTENDED_MESH, in_use, true); - LLExtendedMeshParams *param_block = - (LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH); + LLExtendedMeshParams *param_block = (LLExtendedMeshParams *)getExtendedMeshParams(); if (param_block) { param_block->setFlags(flags); @@ -3842,11 +3857,12 @@ void LLVOVolume::onReparent(LLViewerObject *old_parent, LLViewerObject *new_pare } if (old_volp && old_volp->isAnimatedObject()) { - if (old_volp->getControlAvatar()) + LLControlAvatar* cav = old_volp->getControlAvatar(); + if (cav) { // We have been removed from an animated object, need to do cleanup. - old_volp->getControlAvatar()->updateAttachmentOverrides(); - old_volp->getControlAvatar()->updateAnimations(); + cav->updateAttachmentOverrides(); + cav->updateAnimations(); } } } @@ -5131,7 +5147,7 @@ U32 LLVOVolume::getPartitionType() const { return LLViewerRegion::PARTITION_HUD; } - if (isAnimatedObject() && getControlAvatar()) + if (isAnimatedObjectFast() && getControlAvatar()) { return LLViewerRegion::PARTITION_CONTROL_AV; } @@ -5757,11 +5773,18 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } // Standard rigged mesh attachments: - bool rigged = !vobj->isAnimatedObject() && skinInfo && vobj->isAttachment(); + bool is_animated = vobj->isAnimatedObject(); + bool rigged = !is_animated && skinInfo && vobj->isAttachment(); // Animated objects. Have to check for isRiggedMesh() to // exclude static objects in animated object linksets. - rigged = rigged || (vobj->isAnimatedObject() && vobj->isRiggedMesh() && - vobj->getControlAvatar() && vobj->getControlAvatar()->mPlaying); + if (!rigged && is_animated && vobj->isRiggedMesh()) + { + LLControlAvatar* cav = vobj->getControlAvatar(); + if (cav) + { + rigged = cav->mPlaying; + } + } bool any_rigged_face = false; diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 97a51312609..b6044bc3190 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -227,6 +227,7 @@ class LLVOVolume : public LLViewerObject void setTexture(const S32 face); S32 getIndexInTex(U32 ch) const {return mIndexInTex[ch];} + void unregisterOldMeshAndSkin(); /*virtual*/ bool setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false) override; void updateSculptTexture(); void setIndexInTex(U32 ch, S32 index) { mIndexInTex[ch] = index ;} @@ -283,9 +284,9 @@ class LLVOVolume : public LLViewerObject // Get the light color in sRGB color space scaled by intensity. LLColor3 getLightSRGBColor() const; - LLUUID getLightTextureID() const; + const LLUUID& getLightTextureID() const; bool isLightSpotlight() const; - LLVector3 getSpotLightParams() const; + const LLVector3& getSpotLightParams() const; void updateSpotLightPriority(); F32 getSpotLightPriority() const; diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index cc593fe7b4d..f639024228e 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -82,7 +82,7 @@ LLPanelWearableListItem::LLPanelWearableListItem(LLViewerInventoryItem* item, co ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelWearableOutfitItem(&typeid(LLPanelWearableOutfitItem::Params), "wearable_outfit_list_item"); +static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelWearableOutfitItem(typeid(LLPanelWearableOutfitItem::Params), "wearable_outfit_list_item"); LLPanelWearableOutfitItem::Params::Params() : add_btn("add_btn"), @@ -222,7 +222,7 @@ void LLPanelWearableOutfitItem::updateItem(const std::string& name, ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelClothingListItem(&typeid(LLPanelClothingListItem::Params), "clothing_list_item"); +static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelClothingListItem(typeid(LLPanelClothingListItem::Params), "clothing_list_item"); LLPanelClothingListItem::Params::Params() @@ -309,7 +309,7 @@ bool LLPanelClothingListItem::postBuild() ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelBodyPartsListItem(&typeid(LLPanelBodyPartsListItem::Params), "bodyparts_list_item"); +static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelBodyPartsListItem(typeid(LLPanelBodyPartsListItem::Params), "bodyparts_list_item"); LLPanelBodyPartsListItem::Params::Params() @@ -380,7 +380,7 @@ bool LLPanelBodyPartsListItem::postBuild() return true; } -static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDeletableWearableListItem(&typeid(LLPanelDeletableWearableListItem::Params), "deletable_wearable_list_item"); +static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDeletableWearableListItem(typeid(LLPanelDeletableWearableListItem::Params), "deletable_wearable_list_item"); LLPanelDeletableWearableListItem::Params::Params() : delete_btn("delete_btn") @@ -467,7 +467,7 @@ void LLPanelAttachmentListItem::updateItem(const std::string& name, ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDummyClothingListItem(&typeid(LLPanelDummyClothingListItem::Params), "dummy_clothing_list_item"); +static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDummyClothingListItem(typeid(LLPanelDummyClothingListItem::Params), "dummy_clothing_list_item"); LLPanelDummyClothingListItem::Params::Params() : add_panel("add_panel"), diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index a319aa00bcf..f6032743358 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -34,6 +34,7 @@ #include "llagent.h" #include "llappviewer.h" +#include "llfloatermarketplace.h" #include "llfloaterwebcontent.h" #include "llfloaterreg.h" #include "lllogininstance.h" @@ -74,12 +75,20 @@ void LLWeb::loadURL(const std::string& url, const std::string& target, const std } // static -// Explicitly open a Web URL using the Web content floater +// Explicitly open a Web URL using the Web content floater or Marketplace floater void LLWeb::loadURLInternal(const std::string &url, const std::string& target, const std::string& uuid, bool dev_mode) { LLFloaterWebContent::Params p; p.url(url).target(target).id(uuid).dev_mode(dev_mode); - LLFloaterReg::showInstance("web_content", p); + + if (LLFloaterMarketplace::isMarketplaceURL(url)) + { + LLFloaterReg::showInstance("marketplace", p); + } + else + { + LLFloaterReg::showInstance("web_content", p); + } } // static diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp index 153bee3aef8..1db36649fae 100644 --- a/indra/newview/llworldmap.cpp +++ b/indra/newview/llworldmap.cpp @@ -118,6 +118,7 @@ LLVector3d LLSimInfo::getGlobalOrigin() const { return from_region_handle(mHandle); } + LLVector3 LLSimInfo::getLocalPos(LLVector3d global_pos) const { LLVector3d sim_origin = from_region_handle(mHandle); diff --git a/indra/newview/llworldmap.h b/indra/newview/llworldmap.h index 68e7f3ee29f..91bc6997080 100644 --- a/indra/newview/llworldmap.h +++ b/indra/newview/llworldmap.h @@ -37,18 +37,6 @@ #include "llviewertexture.h" #include "llgltexture.h" -// map item types -const U32 MAP_ITEM_TELEHUB = 0x01; -const U32 MAP_ITEM_PG_EVENT = 0x02; -const U32 MAP_ITEM_MATURE_EVENT = 0x03; -//const U32 MAP_ITEM_POPULAR = 0x04; // No longer supported, 2009-03-02 KLW -//const U32 MAP_ITEM_AGENT_COUNT = 0x05; -const U32 MAP_ITEM_AGENT_LOCATIONS = 0x06; -const U32 MAP_ITEM_LAND_FOR_SALE = 0x07; -const U32 MAP_ITEM_CLASSIFIED = 0x08; -const U32 MAP_ITEM_ADULT_EVENT = 0x09; -const U32 MAP_ITEM_LAND_FOR_SALE_ADULT = 0x0a; - // Description of objects like hubs, events, land for sale, people and more (TBD). // Note: we don't store a "type" in there so we need to store instances of this class in // well known objects (i.e. list of objects which type is "well known"). diff --git a/indra/newview/llworldmapmessage.cpp b/indra/newview/llworldmapmessage.cpp index a5433133ab8..3264f8ae8b2 100644 --- a/indra/newview/llworldmapmessage.cpp +++ b/indra/newview/llworldmapmessage.cpp @@ -34,7 +34,6 @@ #include "llfloaterworldmap.h" constexpr U32 LAYER_FLAG = 2; -constexpr S32 MAP_SIM_RETURN_NULL_SIMS = 0x00010000; //--------------------------------------------------------------------------- // World Map Message Handling diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 6b2bd3e6fb9..1be6a6cfff1 100755 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -517,26 +517,38 @@ void LLWorldMapView::draw() // Draw the region name in the lower left corner if (mMapScale >= DRAW_TEXT_THRESHOLD) { - std::string mesg; + static LLCachedControl print_coords(gSavedSettings, "MapShowGridCoords"); + static LLFontGL* font = LLFontGL::getFontSansSerifSmallBold(); + + auto print = [&](std::string text, F32 x, F32 y, bool use_ellipses) + { + font->renderUTF8(text, 0, + (F32)llfloor(left + x), (F32)llfloor(bottom + y), + LLColor4::white, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW, + S32_MAX, //max_chars + (S32)mMapScale, //max_pixels + NULL, + use_ellipses); + }; + + std::string grid_name = info->getName(); if (info->isDown()) { - mesg = llformat( "%s (%s)", info->getName().c_str(), sStringsMap["offline"].c_str()); + grid_name += " (" + sStringsMap["offline"] + ")"; } - else + + if (print_coords) { - mesg = info->getName(); + print(grid_name, 3, 14, true); + // Obtain and print the grid map coordinates + LLVector3d region_pos = info->getGlobalOrigin(); + std::string grid_coords = llformat("[%.0f, %.0f]", region_pos[VX] / 256, region_pos[VY] / 256); + print(grid_coords, 3, 2, false); } - if (!mesg.empty()) + else { - LLFontGL::getFontSansSerifSmallBold()->renderUTF8( - mesg, 0, - (F32)llfloor(left + 3), (F32)llfloor(bottom + 2), - LLColor4::white, - LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW, - S32_MAX, //max_chars - (S32)mMapScale, //max_pixels - NULL, - /*use_ellipses*/true); + print(grid_name, 3, 2, true); } } } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index d2aebfbce53..c9d53bbcbc0 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -2734,6 +2734,10 @@ void LLPipeline::clearRebuildGroups() { LLSpatialGroup* group = *iter; + if (!group || group->isDead()) + { + continue; + } // If the group contains HUD objects, save the group if (group->isHUDGroup()) { @@ -5525,7 +5529,7 @@ static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_ if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE)) { // moving lights get a little higher priority (too much causes artifacts) - dist = llmax(dist - light->getLightRadius()*0.25f, 0.f); + dist = llmax(dist - radius * 0.25f, 0.f); } return dist; } diff --git a/indra/newview/skins/default/xui/da/floater_sound_devices.xml b/indra/newview/skins/default/xui/da/floater_sound_devices.xml deleted file mode 100644 index cb4cbba5700..00000000000 --- a/indra/newview/skins/default/xui/da/floater_sound_devices.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - Stemme chat - - - diff --git a/indra/newview/skins/default/xui/da/floater_voice_effect.xml b/indra/newview/skins/default/xui/da/floater_voice_effect.xml deleted file mode 100644 index 86ad2511036..00000000000 --- a/indra/newview/skins/default/xui/da/floater_voice_effect.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - (Ingen stemme "morph") - - - (Aktiv) - - - (Ikke aktiveret) - - - (Ny!) - - - For at se - - - Optag en prøve, klik derefter på en stemme for at høre hvordan det vil lyde. - - - - - [[URL] Subscribe Now] - - - - - - - diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml index 0ce64b7a833..b0635a22295 100644 --- a/indra/newview/skins/default/xui/en/floater_world_map.xml +++ b/indra/newview/skins/default/xui/en/floater_world_map.xml @@ -109,7 +109,7 @@ + + + Show grid map coordinates + +