diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..5766126411 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "monthly" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1dd2c1d5df..7b6187f3bb 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -24,6 +24,8 @@ jobs: outputs: viewer_channel: ${{ steps.build.outputs.viewer_channel }} viewer_version: ${{ steps.build.outputs.viewer_version }} + viewer_branch: ${{ steps.which-branch.outputs.branch }} + relnotes: ${{ steps.which-branch.outputs.relnotes }} imagename: ${{ steps.build.outputs.imagename }} env: AUTOBUILD_ADDRSIZE: 64 @@ -33,12 +35,13 @@ jobs: AUTOBUILD_GITHUB_TOKEN: ${{ secrets.SHARED_AUTOBUILD_GITHUB_TOKEN }} AUTOBUILD_INSTALLABLE_CACHE: ${{ github.workspace }}/.autobuild-installables AUTOBUILD_VARIABLES_FILE: ${{ github.workspace }}/.build-variables/variables + # Direct autobuild to store vcs_url, vcs_branch and vcs_revision in + # autobuild-package.xml. + AUTOBUILD_VCS_INFO: "true" AUTOBUILD_VSVER: "170" DEVELOPER_DIR: ${{ matrix.developer_dir }} # Ensure that Linden viewer builds engage Bugsplat. BUGSPLAT_DB: ${{ matrix.configuration != 'ReleaseOS' && 'SecondLife_Viewer_2018' || '' }} - BUGSPLAT_PASS: ${{ secrets.BUGSPLAT_PASS }} - BUGSPLAT_USER: ${{ secrets.BUGSPLAT_USER }} build_coverity: false build_log_dir: ${{ github.workspace }}/.logs build_viewer: true @@ -62,7 +65,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Setup python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -70,7 +73,7 @@ jobs: uses: actions/checkout@v4 with: repository: secondlife/build-variables - ref: viewer + ref: master path: .build-variables - name: Checkout master-message-template @@ -83,7 +86,7 @@ jobs: run: pip3 install autobuild llsd - name: Cache autobuild packages - uses: actions/cache@v3 + uses: actions/cache@v4 id: cache-installables with: path: .autobuild-installables @@ -96,10 +99,17 @@ jobs: if: runner.os == 'Windows' run: choco install nsis-unicode + - name: Determine source branch + id: which-branch + uses: secondlife/viewer-build-util/which-branch@v1 + with: + token: ${{ github.token }} + - name: Build id: build shell: bash env: + AUTOBUILD_VCS_BRANCH: ${{ steps.which-branch.outputs.branch }} RUNNER_OS: ${{ runner.os }} run: | # set up things the viewer's build.sh script expects @@ -150,7 +160,7 @@ jobs: } repo_branch() { - git -C "$1" branch | grep '^* ' | cut -c 3- + echo "$AUTOBUILD_VCS_BRANCH" } record_dependencies_graph() { @@ -214,7 +224,7 @@ jobs: - name: Upload executable if: matrix.configuration != 'ReleaseOS' && steps.build.outputs.viewer_app - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "${{ steps.build.outputs.artifact }}-app" path: | @@ -224,7 +234,7 @@ jobs: # artifact for that too. - name: Upload symbol file if: matrix.configuration != 'ReleaseOS' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "${{ steps.build.outputs.artifact }}-symbols" path: | @@ -232,7 +242,7 @@ jobs: - name: Upload metadata if: matrix.configuration != 'ReleaseOS' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "${{ steps.build.outputs.artifact }}-metadata" # emitted by build.sh, possibly multiple lines @@ -240,7 +250,7 @@ jobs: ${{ steps.build.outputs.metadata }} - name: Upload physics package - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 # should only be set for viewer-private if: matrix.configuration != 'ReleaseOS' && steps.build.outputs.physicstpv with: @@ -250,23 +260,36 @@ jobs: ${{ steps.build.outputs.physicstpv }} sign-and-package-windows: + env: + AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }} + AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} needs: build runs-on: windows steps: - name: Sign and package Windows viewer + if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID uses: secondlife/viewer-build-util/sign-pkg-windows@v1 with: - vault_uri: "${{ secrets.AZURE_KEY_VAULT_URI }}" - cert_name: "${{ secrets.AZURE_CERT_NAME }}" - client_id: "${{ secrets.AZURE_CLIENT_ID }}" - client_secret: "${{ secrets.AZURE_CLIENT_SECRET }}" - tenant_id: "${{ secrets.AZURE_TENANT_ID }}" + vault_uri: "${{ env.AZURE_KEY_VAULT_URI }}" + cert_name: "${{ env.AZURE_CERT_NAME }}" + client_id: "${{ env.AZURE_CLIENT_ID }}" + client_secret: "${{ env.AZURE_CLIENT_SECRET }}" + tenant_id: "${{ env.AZURE_TENANT_ID }}" sign-and-package-mac: + env: + NOTARIZE_CREDS_MACOS: ${{ secrets.NOTARIZE_CREDS_MACOS }} + SIGNING_CERT_MACOS: ${{ secrets.SIGNING_CERT_MACOS }} + SIGNING_CERT_MACOS_IDENTITY: ${{ secrets.SIGNING_CERT_MACOS_IDENTITY }} + SIGNING_CERT_MACOS_PASSWORD: ${{ secrets.SIGNING_CERT_MACOS_PASSWORD }} needs: build runs-on: macos-latest steps: - name: Unpack Mac notarization credentials + if: env.NOTARIZE_CREDS_MACOS id: note-creds shell: bash run: | @@ -274,7 +297,7 @@ jobs: # USERNAME="..." # PASSWORD="..." # TEAM_ID="..." - eval "${{ secrets.NOTARIZE_CREDS_MACOS }}" + eval "${{ env.NOTARIZE_CREDS_MACOS }}" echo "::add-mask::$USERNAME" echo "::add-mask::$PASSWORD" echo "::add-mask::$TEAM_ID" @@ -286,45 +309,54 @@ jobs: [[ -n "$USERNAME" && -n "$PASSWORD" && -n "$TEAM_ID" ]] - name: Sign and package Mac viewer + if: env.SIGNING_CERT_MACOS && env.SIGNING_CERT_MACOS_IDENTITY && env.SIGNING_CERT_MACOS_PASSWORD && steps.note-creds.outputs.note_user && steps.note-creds.outputs.note_pass && steps.note-creds.outputs.note_team uses: secondlife/viewer-build-util/sign-pkg-mac@v1 with: channel: ${{ needs.build.outputs.viewer_channel }} imagename: ${{ needs.build.outputs.imagename }} - cert_base64: ${{ secrets.SIGNING_CERT_MACOS }} - cert_name: ${{ secrets.SIGNING_CERT_MACOS_IDENTITY }} - cert_pass: ${{ secrets.SIGNING_CERT_MACOS_PASSWORD }} + cert_base64: ${{ env.SIGNING_CERT_MACOS }} + cert_name: ${{ env.SIGNING_CERT_MACOS_IDENTITY }} + cert_pass: ${{ env.SIGNING_CERT_MACOS_PASSWORD }} note_user: ${{ steps.note-creds.outputs.note_user }} note_pass: ${{ steps.note-creds.outputs.note_pass }} note_team: ${{ steps.note-creds.outputs.note_team }} post-windows-symbols: + env: + BUGSPLAT_USER: ${{ secrets.BUGSPLAT_USER }} + BUGSPLAT_PASS: ${{ secrets.BUGSPLAT_PASS }} needs: build runs-on: ubuntu-latest steps: - name: Post Windows symbols + if: env.BUGSPLAT_USER && env.BUGSPLAT_PASS uses: secondlife/viewer-build-util/post-bugsplat-windows@v1 with: - username: ${{ secrets.BUGSPLAT_USER }} - password: ${{ secrets.BUGSPLAT_PASS }} + username: ${{ env.BUGSPLAT_USER }} + password: ${{ env.BUGSPLAT_PASS }} database: "SecondLife_Viewer_2018" channel: ${{ needs.build.outputs.viewer_channel }} version: ${{ needs.build.outputs.viewer_version }} post-mac-symbols: + env: + BUGSPLAT_USER: ${{ secrets.BUGSPLAT_USER }} + BUGSPLAT_PASS: ${{ secrets.BUGSPLAT_PASS }} needs: build runs-on: ubuntu-latest steps: - name: Post Mac symbols + if: env.BUGSPLAT_USER && env.BUGSPLAT_PASS uses: secondlife/viewer-build-util/post-bugsplat-mac@v1 with: - username: ${{ secrets.BUGSPLAT_USER }} - password: ${{ secrets.BUGSPLAT_PASS }} + username: ${{ env.BUGSPLAT_USER }} + password: ${{ env.BUGSPLAT_PASS }} database: "SecondLife_Viewer_2018" channel: ${{ needs.build.outputs.viewer_channel }} version: ${{ needs.build.outputs.viewer_version }} release: - needs: [sign-and-package-windows, sign-and-package-mac] + needs: [build, sign-and-package-windows, sign-and-package-mac] runs-on: ubuntu-latest if: github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life_') steps: @@ -355,17 +387,31 @@ jobs: mv newview/viewer_version.txt macOS-viewer_version.txt # forked from softprops/action-gh-release - - uses: secondlife-3p/action-gh-release@v1 + - name: Create GitHub release + id: release + uses: secondlife-3p/action-gh-release@v1 with: - # name the release page for the build number so we can find it - # easily (analogous to looking up a codeticket build page) - name: "v${{ github.run_id }}" + # name the release page for the branch + name: "${{ needs.build.outputs.viewer_branch }}" + # SL-20546: want the channel and version to be visible on the + # release page + body: | + Build ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + ${{ needs.build.outputs.viewer_channel }} + ${{ needs.build.outputs.viewer_version }} + ${{ needs.build.outputs.relnotes }} prerelease: true generate_release_notes: true - # the only reason we generate a GH release is to post build products + target_commitish: ${{ github.sha }} + previous_tag: release + append_body: true fail_on_unmatched_files: true files: | *.dmg *.exe *-autobuild-package.xml *-viewer_version.txt + + - name: post release URL + run: | + echo "::notice::Release ${{ steps.release.outputs.url }}" diff --git a/.github/workflows/build_viewer.yml b/.github/workflows/build_viewer.yml index f50c4b8e8a..803ec090c4 100644 --- a/.github/workflows/build_viewer.yml +++ b/.github/workflows/build_viewer.yml @@ -25,7 +25,7 @@ jobs: build_matrix: strategy: matrix: - os: [macos-11,ubuntu-20.04,windows-2022] + os: [macos-11,ubuntu-22.04,windows-2022] grid: [sl,os] addrsize: [64] runs-on: ${{ matrix.os }} @@ -178,6 +178,8 @@ jobs: echo -n "$FS_CERT_PASS" >${build_secrets_checkout}/code-signing-osx/password.txt echo -n "$NOTARIZE_CREDS" | base64 --decode --output ${build_secrets_checkout}/code-signing-osx/notarize_creds.sh security create-keychain -p "$FS_KEYCHAIN_PASS" ~/Library/Keychains/viewer.keychain + # notarize tool uses a specific database keychain by default we need to override this to ours. + security default-keychain -s viewer.keychain security set-keychain-settings -lut 21600 ~/Library/Keychains/viewer.keychain security unlock-keychain -p "$FS_KEYCHAIN_PASS" ~/Library/Keychains/viewer.keychain security import ${build_secrets_checkout}/code-signing-osx/fs-cert.p12 -P "$FS_CERT_PASS" -A -t cert -f pkcs12 -k ~/Library/Keychains/viewer.keychain diff --git a/.github/workflows/label.yaml b/.github/workflows/label.yaml index 6e41d8aa2d..a34c575680 100644 --- a/.github/workflows/label.yaml +++ b/.github/workflows/label.yaml @@ -9,7 +9,7 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v4 + - uses: actions/labeler@v5 with: configuration-path: .github/labeler.yaml repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml index d626eef38d..dcb64a3b29 100644 --- a/.github/workflows/pre-commit.yaml +++ b/.github/workflows/pre-commit.yaml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: 3.x - - uses: pre-commit/action@v3.0.0 + - uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index 35ac41420c..6d0eaacca5 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -12,12 +12,13 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v6 + - uses: actions/stale@v9 id: stale with: stale-pr-message: This pull request is stale because it has been open 30 days with no activity. Remove stale label or comment or it will be closed in 7 days days-before-stale: 30 - days-before-close: 7 + days-before-close: 7 + days-before-issue-close: -1 exempt-pr-labels: blocked,must,should,keep stale-pr-label: stale - name: Print outputs diff --git a/autobuild.xml b/autobuild.xml index d14e73c8e0..e318ce0cf1 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -22,11 +22,11 @@ archive hash - bcf0f9d160231c52869b8d81014d0ad3afe537fd + 0f6fbb52ffea1a55bf76a84a6688079f95674cbd hash_algorithm sha1 url - https://3p.firestormviewer.org/SDL2-2.28.5-linux64-233480131.tar.bz2 + https://github.com/secondlife/3p-sdl2/releases/download/v2.28.0-1dc88c1/SDL2-2.28.0-linux64-1dc88c1.tar.zst name linux64 @@ -138,9 +138,11 @@ archive hash - 81fe1e927e4fe3c5e5f15ce6219ca883 + 691fef2ddd57d7b6c26e87fc82d9ace3f54e078c + hash_algorithm + sha1 url - https://3p.firestormviewer.org/fltk-1.3.5.202282121-linux64-202282121.tar.bz2 + https://github.com/secondlife/3p-fltk/releases/download/v1.3.9-r1/fltk-1.3.9.8556992788-linux64-8556992788.tar.zst name linux @@ -381,36 +383,6 @@ - SDL - - copyright - Copyright (C) 1997-2012 Sam Lantinga - description - Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer. - license - lgpl - license_file - LICENSES/SDL.txt - name - SDL - platforms - - linux64 - - archive - - hash - 64c1dff0e19792acec7fd32556bf4d7b - url - https://3p.firestormviewer.org/SDL-1.2.15-linux64-181411635.tar.bz2 - - name - linux64 - - - version - 1.2.15 - apr_suite copyright @@ -444,9 +416,11 @@ archive hash - 1c341bdbb5fd0c8a8930f76e6c1647d4 + 95137cd3f4d6ffa5bd7a00d7d91bd8fc272b7ca2 + hash_algorithm + sha1 url - https://3p.firestormviewer.org/apr_suite-1.4.5.230921251-linux64-230921251.tar.bz2 + https://github.com/secondlife/3p-apr_suite/releases/download/v1.7.2-c5f3347/apr_suite-1.7.2-c5f3347-linux64-c5f3347.tar.zst name linux64 @@ -502,11 +476,11 @@ archive hash - 5d1952e270a873d4587f7b943ed6e3f87d5023da + a3bfbdba7e1977e7e65266ec654990bb13994bd3 hash_algorithm sha1 url - https://3p.firestormviewer.org/boost-1.81-linux64-240621158.tar.zst + https://github.com/secondlife/3p-boost/releases/download/v1.81-3d0d7fc/boost-1.81-linux64-3d0d7fc.tar.zst name linux64 @@ -606,11 +580,11 @@ archive hash - 83f9c9aff5a7b96711c04bd33cb453c108dee3a5 + cab0237b5194254c0c0ff6bf77bc6a2f946d4f57 hash_algorithm sha1 url - https://3p.firestormviewer.org/colladadom-2.3.240621210-linux64-240621210.tar.zst + https://github.com/secondlife/3p-colladadom/releases/download/v2.3-2f532e1/colladadom-2.3.2f532e1-linux64-2f532e1.tar.zst name linux64 @@ -664,11 +638,11 @@ archive hash - 64210ab1d7c881dbe5c78ef8f6db5a6d2b27e5d2 + aea0bed0f953a9371b9091f09230b41597f891f7 hash_algorithm sha1 url - https://3p.firestormviewer.org/cubemaptoequirectangular-1.1.0-linux64-213500938.tar.bz2 + https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-cb8785a/cubemaptoequirectangular-1.1.0-linux64-cb8785a.tar.zst name linux64 @@ -874,11 +848,11 @@ archive hash - c036cc042523fb6a3dafb7134f83e52c566c0765 + 5b957aa7f353b10ae17b7119e5b3668f48a35325 hash_algorithm sha1 url - https://3p.firestormviewer.org/emoji_shortcodes-6.1.0.240620448-linux64-240620448.tar.zst + https://github.com/secondlife/3p-emoji-shortcodes/releases/download/v6.1.0.5413f58/emoji_shortcodes-6.1.0.5413f58-linux64-5413f58.tar.zst name linux64 @@ -932,9 +906,11 @@ archive hash - 39702f98867a319b090ee04f22d82762 + 4cd82e2dec06ddff19e9b3dc0254f2593ec80452 + hash_algorithm + sha1 url - https://3p.firestormviewer.org/expat-2.5.0.230021327-linux64-230021327.tar.bz2 + https://github.com/secondlife/3p-expat/releases/download/v2.1.1.1f36d02/expat-2.1.1.1f36d02-linux64-1f36d02.tar.zst name linux64 @@ -1017,36 +993,6 @@ version 2.02.20 - fontconfig - - copyright - Copyright (C) 2000,2001,2002,2003,2004,2006,2007 Keith Packard, 2005 Patrick Lam, 2009 Roozbeh Pournader, 2008,2009 Red Hat, Inc., 2008 Danilo Šegan, 2012 Google, Inc. - description - Fontconfig is a library for configuring and customizing font access. - license - bsd - license_file - LICENSES/fontconfig.txt - name - fontconfig - platforms - - linux64 - - archive - - hash - 6fdcfcc9aa1d01164c0f7ca5590859bb - url - https://3p.firestormviewer.org/fontconfig-2.12.6-linux64-223020909.tar.bz2 - - name - linux64 - - - version - 2.11.0 - freetype copyright @@ -1080,11 +1026,11 @@ archive hash - a8326f592bf608095f0854383eec2baf36257ea9 + 07a38133c008ce6f728d652d00a756bea3a70288 hash_algorithm sha1 url - https://3p.firestormviewer.org/freetype-2.12.1.240700637-linux64-240700637.tar.zst + https://github.com/secondlife/3p-freetype/releases/download/v2.12.1-r1/freetype-2.12.1.8503093630-linux64-8503093630.tar.zst name linux64 @@ -1229,34 +1175,6 @@ version 1.7.0.2b109d4 - gstreamer - - copyright - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - license - LGPL - license_file - LICENSES/gstreamer.txt - name - gstreamer - platforms - - linux64 - - archive - - hash - 86a358f1b5a2c2baf68444b2bfc5bb32 - url - https://3p.firestormviewer.org/gstreamer-0.10.6.180841551-linux64-180841551.tar.bz2 - - name - linux64 - - - version - 0.10.6.314267 - havok-source copyright @@ -1354,11 +1272,11 @@ archive hash - f5e5be3af96f1eb0842219a94765c04aa9c561c5 + bdd74e2a02c7b78fded9222140d197da4af9904e hash_algorithm sha1 url - https://3p.firestormviewer.org/icu4c-4.8.1-linux64-240621048.tar.zst + https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-8bff176/icu4c-4.8.1-linux64-8512575562.tar.zst name linux64 @@ -1412,9 +1330,11 @@ archive hash - fd8060aa3c920e0fc63e7ecbea67bc5e + 23daab838f4b8f92e5dc1a2f6c568cb7b0cb43b7 + hash_algorithm + sha1 url - https://3p.firestormviewer.org/jpegencoderbasic-1.0-linux64-213500937.tar.bz2 + https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-790015a/jpegencoderbasic-1.0-linux64-790015a.tar.zst name linux64 @@ -1470,9 +1390,11 @@ archive hash - 324bb9deb00d256a12f8cbf686f413f0 + b4b2278bd2fcae85619e2145a243cca388d760d7 + hash_algorithm + sha1 url - https://3p.firestormviewer.org/jpeglib-8c.180841548-linux64-180841548.tar.bz2 + https://github.com/secondlife/3p-jpeglib/releases/download/v8c.7846234/jpeglib-8c.7846234-linux64-7846234.tar.zst name linux64 @@ -1528,9 +1450,11 @@ archive hash - 352ab340f2091c93eb313cf80ac0c8cc + 66dce1d0c2fc19dff13db279d973773fc7e2aa13 + hash_algorithm + sha1 url - https://3p.firestormviewer.org/jsoncpp-0.5.0.202052209-linux64-202052209.tar.bz2 + https://github.com/secondlife/3p-jsoncpp/releases/download/v0.5.0-cc63e92/jsoncpp-0.5.0.cc63e92-linux64-cc63e92.tar.zst name linux64 @@ -1640,9 +1564,11 @@ archive hash - 6555f040c686d8c1dec8e6264c2d3672 + 6413d3bd4cd50c2a6b7f949eb4bd6f0c94feb984 + hash_algorithm + sha1 url - https://3p.firestormviewer.org/libhunspell-1.3.2.180841552-linux64-180841552.tar.bz2 + https://github.com/secondlife/3p-libhunspell/releases/download/v1.3.2.650fb94/libhunspell-1.3.2.650fb94-linux64-650fb94.tar.zst name linux64 @@ -1744,11 +1670,11 @@ archive hash - e646a9da0ddfe1dfbffc6600d7d35f78ac48c75e + 39d5779fd79e23da16a7b5bf608008999004c828 hash_algorithm sha1 url - https://3p.firestormviewer.org/libpng-1.6.38-240620624-linux64-240620624.tar.zst + https://github.com/secondlife/3p-libpng/releases/download/v1.16.38-d427738/libpng-1.6.38-8318603154-linux64-8318603154.tar.zst name linux64 @@ -1909,18 +1835,18 @@ archive hash - e50ea94bbaa4ff41bf53b84b7192df1a694c5337 + 3a3e14563cd5fc019c3f139b82aa46ec79847709 hash_algorithm sha1 url - https://github.com/secondlife/llca/releases/download/v202310121525.0-d22bd98/llca-202310121530.0-common-d22bd98.tar.zst + https://github.com/secondlife/llca/releases/download/v202312051403.17-0f5d9c3/llca-202312051404.0-common-0f5d9c3.tar.zst name common version - 202310121530.0 + 202312051404.0 llphysicsextensions_source @@ -1941,11 +1867,11 @@ creds github hash - 48bca5d0233d1e724a59f649a2c6c7ac5f40ec3c + b037cc0b29ea70ee834cfae6dda5b7a25cd57174 hash_algorithm sha1 url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/117009335 + https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/144851460 name darwin64 @@ -1957,11 +1883,11 @@ creds github hash - 39f52d0350e130f41c5c758f7cb94e87b962c223 + bdea1fd5c4da9da5afde088d16188b45d0853e04 hash_algorithm sha1 url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/117009336 + https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/144851461 name linux64 @@ -1973,11 +1899,11 @@ creds github hash - 7b5e645fb7eb399abbea63bd21e8063bbb32a911 + f652ce0d6aef864689f0ed44255da4d9cd65a43f hash_algorithm sha1 url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/117009339 + https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/144851463 name windows64 @@ -2151,9 +2077,11 @@ archive hash - 50d647afc4e510af72f09dcd7a77e920 + 6f4509dca9e32e3b4f9c4b13d875ce0e24340efc + hash_algorithm + sha1 url - https://3p.firestormviewer.org/meshoptimizer-0.16.222121104-linux64-222121104.tar.bz2 + https://github.com/secondlife/3p-meshoptimizer/releases/download/v160-4f905dd/meshoptimizer-160-linux64-4f905dd.tar.zst name linux64 @@ -2178,18 +2106,6 @@ mikktspace - canonical_repo - https://bitbucket.org/lindenlab/3p-mikktspace - copyright - Copyright (C) 2011 by Morten S. Mikkelsen - description - Mikktspace Tangent Generator - license - Copyright (C) 2011 by Morten S. Mikkelsen - license_file - mikktspace.txt - name - mikktspace platforms darwin64 @@ -2197,52 +2113,58 @@ archive hash - b48b7ac0792d3ea8f087d99d9e4a29d8 + 6cc1585dba85b0226a2e7033a7e2a2ceaae7c983 + hash_algorithm + sha1 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104415/914944/mikktspace-1-darwin64-574859.tar.bz2 + https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-darwin64-5cee1f4.tar.zst name darwin64 - linux64 - - archive - - hash - 5b719b8d3602f8dc9401cc92d606b34e - url - https://3p.firestormviewer.org/mikktspace-1-linux64-223421209.tar.bz2 - - name - linux64 - - windows - - archive - - hash - 0a016b9c0c1e2c0b557e0124094da6c5 - url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104407/914918/mikktspace-1-windows-574859.tar.bz2 - - name - windows - windows64 archive hash - 02e9e5b6fe6788f4d2babb83ec544843 + 6b7d01ad54e4a88a001f66840c32329cedb28202 + hash_algorithm + sha1 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104406/914909/mikktspace-1-windows64-574859.tar.bz2 + https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-windows64-5cee1f4.tar.zst name windows64 + linux64 + + archive + + hash + edc9782bf209e17ad1845498b42f16d733582082 + hash_algorithm + sha1 + url + https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-linux64-5cee1f4.tar.zst + + name + linux64 + + license + Copyright (C) 2011 by Morten S. Mikkelsen + license_file + mikktspace.txt + copyright + Copyright (C) 2011 by Morten S. Mikkelsen version 1 + name + mikktspace + canonical_repo + https://bitbucket.org/lindenlab/3p-mikktspace + description + Mikktspace Tangent Generator minizip-ng @@ -2490,9 +2412,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 03b7df0406d7588c4fb49c2ddf0d8264 + 90052be851c4fcecc35d8424b4f31352de14ab2f + hash_algorithm + sha1 url - https://3p.firestormviewer.org/ogg_vorbis-1.3.3-1.3.6.202241500-linux64-202241500.tar.bz2 + https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.3-1.3.6-881f65e/ogg_vorbis-1.3.3-1.3.6.881f65e-linux64-881f65e.tar.zst name linux64 @@ -2536,11 +2460,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 52c4622c76c773deba056eeb6b0dc726cb3100bd + 2d20683554f0b00234bbb84d0ce7ac1be1ad70aa hash_algorithm sha1 url - https://3p.firestormviewer.org/open_libndofdev-0.14.233480318-linux64-233480318.tar.bz2 + https://github.com/secondlife/3p-open-libndofdev/releases/download/v1.14-r1/open_libndofdev-0.14.8503290964-linux64-8503290964.tar.zst name linux64 @@ -2582,9 +2506,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 4f36ae378593240701fd4453bd6074c8 + e0fbc4874acc4167a6e2b6489fbb8258d98fd665 + hash_algorithm + sha1 url - https://3p.firestormviewer.org/openal-1.12.854-1.1.0.180841552-linux64-180841552.tar.bz2 + https://github.com/secondlife/3p-openal-soft/releases/download/v1.23.1-18e315c/openal-1.23.1-linux64-18e315c.tar.zst name linux64 @@ -2640,9 +2566,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - b1dad7c841118a3b6e03a01722d1846a + 8c277dde6076fb682cb07264dd70f6f2298b633f + hash_algorithm + sha1 url - https://3p.firestormviewer.org/openjpeg-2.5.0.230362345-linux64-230362345.tar.bz2 + https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.0.ea12248/openjpeg-2.5.0.ea12248-linux64-ea12248.tar.zst name linux64 @@ -2870,9 +2798,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - d37be064bd851276dab423d723cb9b7d + 982c0fa427458082ea9e3cb9603904210732b64e + hash_algorithm + sha1 url - https://3p.firestormviewer.org/threejs-0.132.2-linux64-213500940.tar.bz2 + https://github.com/secondlife/3p-three_js/releases/download/v0.132.2-5da28d9/threejs-0.132.2-common-8454371083.tar.zst name linux64 @@ -2897,18 +2827,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors tinygltf - canonical_repo - https://bitbucket.org/lindenlab/3p-tinygltf - copyright - // Copyright (c) 2015 - Present Syoyo Fujita, Aurélien Chatelain and many contributors. - description - tinygltf import library - license - MIT - license_file - LICENSES/tinygltf_license.txt - name - tinygltf platforms common @@ -2916,20 +2834,34 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 4dad1c0948141e1667c01a3ee755e4dc + 2c47ae2d0c38c86b8c2db8d9317f0ab15edfc74f + hash_algorithm + sha1 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/105849/926137/tinygltf-v2.5.0-common-575729.tar.bz2 + https://github.com/secondlife/3p-tinygltf/releases/download/v2.5.0-1ae57fd/tinygltf-v2.5.0-common-1ae57fd.tar.zst name common + license + MIT + license_file + LICENSES/tinygltf_license.txt + copyright + // Copyright (c) 2015 - Present Syoyo Fujita, Aurélien Chatelain and many contributors. + version + v2.5.0 + name + tinygltf + canonical_repo + https://bitbucket.org/lindenlab/3p-tinygltf + description + tinygltf import library source https://bitbucket.org/lindenlab/3p-tinygltf source_type git - version - v2.5.0 tracy @@ -2952,9 +2884,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 9b6e1a1f4b0969d38a1ca8ee00aeb548 + 49650353442698c3e05102676fe427d0ebe02f0b + hash_algorithm + sha1 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/110584/960613/tracy-v0.8.1.578241-darwin64-578241.tar.bz2 + https://github.com/secondlife/3p-tracy/releases/download/v0.8.1-eecbf72/tracy-v0.8.1-eecbf72-darwin64-eecbf72.tar.zst name darwin64 @@ -2964,22 +2898,34 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 05b72ae5d733aed7d3bf142287601cc6 + 2b80e7407e4f3e82eff3879add0e9ad63e7fcace hash_algorithm - md5 + sha1 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/110586/960637/tracy-v0.8.1.578241-windows64-578241.tar.bz2 + https://github.com/secondlife/3p-tracy/releases/download/v0.8.1-eecbf72/tracy-v0.8.1-eecbf72-windows64-eecbf72.tar.zst name windows64 + license + bsd + license_file + LICENSES/tracy_license.txt + copyright + Copyright (c) 2017-2022, Bartosz Taudul (wolf@nereid.pl) + version + v0.8.1-eecbf72 + name + tracy + canonical_repo + https://bitbucket.org/lindenlab/3p-tracy + description + Tracy Profiler Library source https://bitbucket.org/lindenlab/3p-tracy source_type git - version - v0.8.1.578241 tut @@ -3046,9 +2992,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 0d6832fd958ec127f089e683c9b67169 + df66574b3d70f49570709eccd8a1cdeee996cb43 + hash_algorithm + sha1 url - https://3p.firestormviewer.org/uriparser-0.9.4-linux64-211210958.tar.bz2 + https://github.com/secondlife/3p-uriparser/releases/download/v0.9.4-42d7a6d/uriparser-0.9.4-linux64-42d7a6d.tar.zst name linux64 @@ -3369,7 +3317,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors xmlrpc-epi platforms - darwin64 + common archive @@ -3381,7 +3329,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-darwin64-8a05acf.tar.zst name - darwin64 + common linux64 @@ -3434,58 +3382,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - e4f77ba0a9b8ec3cc3fabc51c4da81d2 + 1a73c476b371b62066d1c3eced249660e9467e53 + hash_algorithm + sha1 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/110070/956941/xxhash-0.8.1.578006-windows-578006.tar.bz2 + https://github.com/secondlife/3p-xxhash/releases/download/v0.8.1-69ff69a/xxhash-0.8.1-69ff69a-common-69ff69a.tar.zst name common - darwin64 - - archive - - hash - fdcc803a76a3359bb426db7dac161406676d51e7 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-xxhash/releases/download/v0.8.1.7501c90/xxhash-0.8.1.7501c90-darwin64-7501c90.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 7acb3f94a549fbb9bd7bc16604e34f33c5365a9b - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-xxhash/releases/download/v0.8.1.7501c90/xxhash-0.8.1.7501c90-linux64-7501c90.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 4522d075ea4703ef4b527c3039864ef735ea7953 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-xxhash/releases/download/v0.8.1.7501c90/xxhash-0.8.1.7501c90-windows64-7501c90.tar.zst - - name - windows64 - version - 0.8.1.7501c90 + 0.8.1-69ff69a zlib-ng diff --git a/build.sh b/build.sh index bf90465f9a..c55179f423 100755 --- a/build.sh +++ b/build.sh @@ -112,7 +112,8 @@ installer_CYGWIN() fi } -[[ -n "$GITHUB_OUTPUT" ]] || fatal "Need to export GITHUB_OUTPUT" +# if someone wants to run build.sh outside the GitHub environment +[[ -n "$GITHUB_OUTPUT" ]] || export GITHUB_OUTPUT='/dev/null' # The following is based on the Warning for GitHub multiline output strings: # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) @@ -175,28 +176,6 @@ pre_build() VIEWER_SYMBOL_FILE="$(native_path "$abs_build_dir/newview/$variant/secondlife-symbols-$symplat-${AUTOBUILD_ADDRSIZE}.tar.bz2")" fi - # expect these variables to be set in the environment from GitHub secrets - if [[ -n "$BUGSPLAT_DB" ]] - then - # don't spew credentials into build log - set +x - if [[ -z "$BUGSPLAT_USER" || -z "$BUGSPLAT_PASS" ]] - then - # older mechanism involving build-secrets repo - - # if build_secrets_checkout isn't set, report its name - bugsplat_sh="${build_secrets_checkout:-\$build_secrets_checkout}/bugsplat/bugsplat.sh" - if [ -r "$bugsplat_sh" ] - then # show that we're doing this, just not the contents - echo source "$bugsplat_sh" - source "$bugsplat_sh" - else - fatal "BUGSPLAT_USER or BUGSPLAT_PASS missing, and no $bugsplat_sh" - fi - fi - set -x - export BUGSPLAT_USER BUGSPLAT_PASS - fi - # honor autobuild_configure_parameters same as sling-buildscripts eval_autobuild_configure_parameters=$(eval $(echo echo $autobuild_configure_parameters)) diff --git a/doc/building_linux.md b/doc/building_linux.md index 7455f36feb..eeeb950728 100644 --- a/doc/building_linux.md +++ b/doc/building_linux.md @@ -3,18 +3,23 @@ > [!WARNING] > Please note that we do not give support for compiling the viewer on your own. However, there is a self-compilers group in Second Life that can be joined to ask questions related to compiling the viewer: [Firestorm Self Compilers](https://tinyurl.com/firestorm-self-compilers) -> [!NOTE] -> These instructions only apply to Firestorm versions with AlexIvy code. - This procedure is based on discussions with the Firestorm Linux development team and is the only one recommended for Firestorm for Linux. System requirements are: -- Ubuntu 20.04 x64 fully upgraded +- Ubuntu 22.04 LTS (x86_64) - fully upgraded (this is also now the minimum requirement for running the viewer). - 16GB or more RAM ([Low Memory Caution](#common-issuesbugsglitches-and-solutions)) - 64GB hard drive space - 4 or more core CPU (you could get by with 2 cores, but the process will take much longer) +- GCC 11 compiler (which is the default version on Ubuntu 22.04 LTS) -Due to the age of the build OS, it is recommended that you use a virtual machine, ensuring the guest can meet the hardware requirements. +It is recommended that you use a virtual machine for compiling, ensuring the guest can meet the hardware requirements. -This procedure may or may not work on other Linux distributions. +This procedure may or may not work on other Linux distributions (or you might need to adjust some of the package names to suit the distribution you are using). + +> [!WARNING] +> A system with a glibc version of at least 2.34 is required (Ubuntu 22.04 LTS meets this requirement) +> Building on a system with a glibc version older than 2.34 will likely result in linker errors. + +> [!IMPORTANT] +> Only 64 bit builds are possible - 32 bit support was dropped quite some time ago. ## Establish your programming environment @@ -31,35 +36,22 @@ A few packages must be installed on the build system. Some may already be instal | | | | | | | | --------------- | ---------------- | ------------- | ------------------ | ---------------- | ------ | | libgl1-mesa-dev | libglu1-mesa-dev | libpulse-dev | build-essential | python3-pip | git | -| libssl-dev | libxinerama-dev | libxrandr-dev | libfontconfig1-dev | libfreetype6-dev | gcc-10 | -| | | | | | | +| libssl-dev | libxinerama-dev | libxrandr-dev | libfontconfig-dev | libfreetype6-dev | gcc-11 | +| cmake | | | | | | ``` -sudo apt install libgl1-mesa-dev libglu1-mesa-dev libpulse-dev build-essential python3-pip git libssl-dev libxinerama-dev libxrandr-dev libfontconfig1-dev libfreetype6-dev gcc-10 -``` - -### CMake - -CMake version 3.18 is required but not available in Ubuntu's repositories, we have to build it from source - -``` -wget https://github.com/Kitware/CMake/releases/download/v3.18.0/cmake-3.18.0.tar.gz -tar xvf cmake-3.18.0.tar.gz -cd cmake-3.18.0 -./bootstrap --parallel=$(nproc) --prefix=/usr && make -j $(nproc) && sudo make install +sudo apt install libgl1-mesa-dev libglu1-mesa-dev libpulse-dev build-essential python3-pip git libssl-dev libxinerama-dev libxrandr-dev libfontconfig-dev libfreetype6-dev gcc-11 cmake ``` ### Install Autobuild Autobuild is a Linden Lab resource that does all the hard work. - +You can install it using the same versions as our automated builds as follows: ``` sudo pip3 install --upgrade pip -sudo pip3 install git+https://github.com/secondlife/autobuild.git#egg=autobuild +pip install -r requirements.txt ``` - -Check Autobuild version to be "autobuild 3.8" or higher: `autobuild --version` - +Check Autobuild version to be "autobuild 3.9.3" or higher: `autobuild --version` ## Download the source code There are two required repositories, the viewer itself and the build variables. An optional third repository is used to configure and package FMOD Studio. @@ -81,7 +73,7 @@ The rest of this document will assume the default directory, `phoenix-firestorm` ### Clone the Autobuild build variables -Autobuild 3.0 uses a separate file to control compiler options, switches, and the like for different configurations. +Autobuild uses a separate file to control compiler options, switches, and the like for different configurations. ``` cd ~/src diff --git a/doc/building_macos.md b/doc/building_macos.md index f5ad4ea481..ce251a4673 100644 --- a/doc/building_macos.md +++ b/doc/building_macos.md @@ -40,7 +40,7 @@ sudo python3 get-pip.py The Linden Lab [Autobuild](https://github.com/secondlife/autobuild) tool. - Use the following command to install it on your machine: ``` -pip3 install --user git+https://bitbucket.org/lindenlab/autobuild.git#egg=autobuild +pip3 install --user -r requirements.txt ``` - Add it to your PATH environment variable so it can be found by the shell. The macOS-approved way to do this is to issue the following command (This change will not take effect until the next time you open a Terminal window.): @@ -53,7 +53,7 @@ echo '~/Library/Python/3.7/bin/' | sudo tee /etc/paths.d/99-autobuild export PATH=$PATH:~/Library/Python/3.7/bin/ ``` -- Check Autobuild version to be "autobuild 3.8" or higher: `autobuild --version` +- Check Autobuild version to be "autobuild 3.9.3" or higher: `autobuild --version` ### Additional third party libraries If you want to use licensed FMOD Studio API or KDU build libraries (they are optional) you have to provide these yourself. If you're building Firestorm as part of the project team, ask for the libraries for fmodstudio and kdu. Put them into `/opt/firestorm`. diff --git a/doc/building_windows.md b/doc/building_windows.md index 46117d7fbc..7ae61cdf5e 100644 --- a/doc/building_windows.md +++ b/doc/building_windows.md @@ -93,9 +93,11 @@ If they all report sensible values and not "Command not found" errors, then you ### Set up Autobuild - Install Autobuild + You can install autobuild and its dependencies using the `requirements.txt` file that is part of the repo, this will build using the same versions that our official builds use. + - Open Windows Command Prompt and enter: pip install -r requirements.txt + - Autobuild will be installed. **Earlier versions of Autobuild could be made to work by just putting the source files into your path correctly; this is no longer true - Autobuild _must_ be installed as described here.** - Open Windows Command Prompt and enter: `pip install git+https://github.com/secondlife/autobuild.git#egg=autobuild` - - Autobuild will be installed. **Earlier versions of Autobuild could be made to work by just putting the source files into your path correctly; this is no longer true - Autobuild _must_ be installed as described here.** - Set environment variable AUTOBUILD_VSVER to 170 (170 = Visual Studio 2022). - Check Autobuild version to be "autobuild 3.8" or higher: `autobuild --version` diff --git a/doc/contributions.txt b/doc/contributions.txt index 818cd384dc..8dbd423c27 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -296,6 +296,7 @@ Beq Janus SL-18637 SL-19317 SL-19660 + SL-20610 Beth Walcher Bezilon Kasei Biancaluce Robbiani diff --git a/doc/testplans/optimize_away_alpha.md b/doc/testplans/optimize_away_alpha.md new file mode 100644 index 0000000000..f0c8d1e8d6 --- /dev/null +++ b/doc/testplans/optimize_away_alpha.md @@ -0,0 +1,5 @@ +Textures imported via Build->Upload->Material that have an all opaque (255) alpha channel should have their alpha channel removed before upload. + +1. Make 4 images that have different colors but all 255 alpha channels +2. Upload them all using Build->Upload->Material, with one in each of the material texture slots +3. Verify that using the textures as a blinn-phong diffuse map does not make the corresponding face render in the alpha pass (face should stay visible after disabling alpha pass by unchecking Advanced->Render Types->Alpha). diff --git a/indra/cmake/JsonCpp.cmake b/indra/cmake/JsonCpp.cmake index 35fc6090cd..a9b992ab20 100644 --- a/indra/cmake/JsonCpp.cmake +++ b/indra/cmake/JsonCpp.cmake @@ -12,6 +12,6 @@ if (WINDOWS) elseif (DARWIN) target_link_libraries( ll::jsoncpp INTERFACE libjson_darwin_libmt.a ) elseif (LINUX) - target_link_libraries( ll::jsoncpp INTERFACE libjson_linux-gcc-5.4.0_libmt.a ) + target_link_libraries( ll::jsoncpp INTERFACE libjson_linux-gcc-11_libmt.a ) endif (WINDOWS) target_include_directories( ll::jsoncpp SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) diff --git a/indra/llcommon/classic_callback.h b/indra/llcommon/classic_callback.h index 1ad6dbc58f..009c25d67c 100644 --- a/indra/llcommon/classic_callback.h +++ b/indra/llcommon/classic_callback.h @@ -119,11 +119,11 @@ public: * ClassicCallback must not itself be copied or moved! Once you've passed * get_userdata() to some API, this object MUST remain at that address. */ - // However, we can't yet count on C++17 Class Template Argument Deduction, - // which means makeClassicCallback() is still useful, which means we MUST - // be able to return one to construct into caller's instance (move ctor). - // Possible defense: bool 'referenced' data member set by get_userdata(), - // with an llassert_always(! referenced) check in the move constructor. + // However, makeClassicCallback() is useful for deducing the CALLABLE + // type, which means we MUST be able to return one to construct into + // caller's instance (move ctor). Possible defense: bool 'referenced' data + // member set by get_userdata(), with an llassert_always(! referenced) + // check in the move constructor. ClassicCallback(ClassicCallback const&) = delete; ClassicCallback(ClassicCallback&&) = default; // delete; ClassicCallback& operator=(ClassicCallback const&) = delete; diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp index 1b48e4daf3..9a0c565b06 100644 --- a/indra/llcommon/indra_constants.cpp +++ b/indra/llcommon/indra_constants.cpp @@ -50,6 +50,7 @@ const LLUUID IMG_FIRE ("aca40aa8-44cf-44ca-a0fa-93e1a2986f82"); // dataserver const LLUUID IMG_FACE_SELECT ("a85ac674-cb75-4af6-9499-df7c5aaf7a28"); // face selector const LLUUID IMG_DEFAULT_AVATAR ("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"); // dataserver const LLUUID IMG_INVISIBLE ("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"); // dataserver +const LLUUID IMG_WHITE ("5748decc-f629-461c-9a36-a35a221fe21f"); // dataserver const LLUUID IMG_EXPLOSION ("68edcf47-ccd7-45b8-9f90-1649d7f12806"); // On dataserver const LLUUID IMG_EXPLOSION_2 ("21ce046c-83fe-430a-b629-c7660ac78d7c"); // On dataserver @@ -71,6 +72,11 @@ const LLUUID TERRAIN_ROCK_DETAIL ("53a2f406-4895-1d13-d541-d2e3b86bc19c"); // V const LLUUID DEFAULT_WATER_NORMAL ("822ded49-9a6c-f61c-cb89-6df54f42cdf4"); // VIEWER +const LLUUID DEFAULT_OBJECT_TEXTURE ("89556747-24cb-43ed-920b-47caed15465f"); // On dataserver +const LLUUID DEFAULT_OBJECT_SPECULAR ("87e0e8f7-8729-1ea8-cfc9-8915773009db"); // On dataserver +const LLUUID DEFAULT_OBJECT_NORMAL ("85f28839-7a1c-b4e3-d71d-967792970a7b"); // On dataserver +const LLUUID BLANK_OBJECT_NORMAL ("5b53359e-59dd-d8a2-04c3-9e65134da47a"); // VIEWER (has a verion on dataserver, but with compression artifacts) + const LLUUID IMG_USE_BAKED_HEAD ("5a9f4a74-30f2-821c-b88d-70499d3e7183"); const LLUUID IMG_USE_BAKED_UPPER ("ae2de45c-d252-50b8-5c6e-19f39ce79317"); const LLUUID IMG_USE_BAKED_LOWER ("24daea5f-0539-cfcf-047f-fbc40b2786ba"); diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index ead46bfa5f..6dc88a538f 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -201,6 +201,7 @@ LL_COMMON_API extern const LLUUID IMG_FIRE; LL_COMMON_API extern const LLUUID IMG_FACE_SELECT; LL_COMMON_API extern const LLUUID IMG_DEFAULT_AVATAR; LL_COMMON_API extern const LLUUID IMG_INVISIBLE; +LL_COMMON_API extern const LLUUID IMG_WHITE; LL_COMMON_API extern const LLUUID IMG_EXPLOSION; LL_COMMON_API extern const LLUUID IMG_EXPLOSION_2; @@ -234,6 +235,10 @@ LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX3; LL_COMMON_API extern const LLUUID DEFAULT_WATER_NORMAL; +LL_COMMON_API extern const LLUUID DEFAULT_OBJECT_TEXTURE; +LL_COMMON_API extern const LLUUID DEFAULT_OBJECT_SPECULAR; +LL_COMMON_API extern const LLUUID DEFAULT_OBJECT_NORMAL; +LL_COMMON_API extern const LLUUID BLANK_OBJECT_NORMAL; // radius within which a chat message is fully audible const F32 CHAT_NORMAL_RADIUS = 20.f; diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index e3bb661c63..d1457a4e0e 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -104,7 +104,6 @@ BOOL LLApp::sLogInSignal = FALSE; // Keeps track of application status LLScalarCond LLApp::sStatus{LLApp::APP_STATUS_STOPPED}; LLAppErrorHandler LLApp::sErrorHandler = NULL; -BOOL LLApp::sErrorThreadRunning = FALSE; LLApp::LLApp() @@ -793,13 +792,8 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) return; } - // Flag status to ERROR, so thread_error does its work. + // Flag status to ERROR LLApp::setError(); - // Block in the signal handler until somebody says that we're done. - while (LLApp::sErrorThreadRunning && !LLApp::isStopped()) - { - ms_sleep(10); - } if (LLApp::sLogInSignal) { diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index c832c8b142..a892bfeb1e 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -291,7 +291,6 @@ protected: static void setStatus(EAppStatus status); // Use this to change the application status. static LLScalarCond sStatus; // Reflects current application status - static BOOL sErrorThreadRunning; // Set while the error thread is running static BOOL sDisableCrashlogger; // Let the OS handle crashes for us. std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting. diff --git a/indra/llcommon/llbase64.cpp b/indra/llcommon/llbase64.cpp index bb85fe32a3..433b54f6f8 100644 --- a/indra/llcommon/llbase64.cpp +++ b/indra/llcommon/llbase64.cpp @@ -42,7 +42,7 @@ std::string LLBase64::encode(const U8* input, size_t input_size) && input_size > 0) { // Yes, it returns int. - int b64_buffer_length = apr_base64_encode_len(narrow(input_size)); + int b64_buffer_length = apr_base64_encode_len(narrow(input_size)); char* b64_buffer = new char[b64_buffer_length]; // This is faster than apr_base64_encode() if you know @@ -52,7 +52,7 @@ std::string LLBase64::encode(const U8* input, size_t input_size) b64_buffer_length = apr_base64_encode_binary( b64_buffer, input, - narrow(input_size)); + narrow(input_size)); output.assign(b64_buffer); delete[] b64_buffer; } diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 3ab97b557f..c13900f74a 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -123,7 +123,7 @@ LLCoros::LLCoros(): // Previously we used // boost::context::guarded_stack_allocator::default_stacksize(); // empirically this is insufficient. - mStackSize(768*1024), + mStackSize(900*1024), // mCurrent does NOT own the current CoroData instance -- it simply // points to it. So initialize it with a no-op deleter. mCurrent{ [](CoroData*){} } @@ -278,6 +278,7 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl catch (std::bad_alloc&) { // Out of memory on stack allocation? + LLError::LLUserWarningMsg::showOutOfMemory(); printActiveCoroutines(); LL_ERRS("LLCoros") << "Bad memory allocation in LLCoros::launch(" << prefix << ")!" << LL_ENDL; } diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h index 5800ec5e5d..18664e340e 100644 --- a/indra/llcommon/lldictionary.h +++ b/indra/llcommon/lldictionary.h @@ -87,11 +87,10 @@ protected: } void addEntry(Index index, Entry *entry) { - if (lookup(index)) + if (!this->emplace(index, entry).second) { LL_ERRS() << "Dictionary entry already added (attempted to add duplicate entry)" << LL_ENDL; } - (*this)[index] = entry; } }; diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 0cd494bc96..87fc5b1922 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -1619,6 +1619,48 @@ namespace LLError { return out << boost::stacktrace::stacktrace(); } + + // LLOutOfMemoryWarning + std::string LLUserWarningMsg::sLocalizedOutOfMemoryTitle; + std::string LLUserWarningMsg::sLocalizedOutOfMemoryWarning; + LLUserWarningMsg::Handler LLUserWarningMsg::sHandler; + + void LLUserWarningMsg::show(const std::string& message) + { + if (sHandler) + { + sHandler(std::string(), message); + } + } + + void LLUserWarningMsg::showOutOfMemory() + { + if (sHandler && !sLocalizedOutOfMemoryTitle.empty()) + { + sHandler(sLocalizedOutOfMemoryTitle, sLocalizedOutOfMemoryWarning); + } + } + + void LLUserWarningMsg::showMissingFiles() + { + // Files Are missing, likely can't localize. + const std::string error_string = + "Firestorm viewer couldn't access some of the files it needs and will be closed." + "\n\nPlease reinstall viewer from https://firestormviewer.org/download and " + "contact https://www.firestormviewer.org/support if issue persists after reinstall."; + sHandler("Missing Files", error_string); + } + + void LLUserWarningMsg::setHandler(const LLUserWarningMsg::Handler &handler) + { + sHandler = handler; + } + + void LLUserWarningMsg::setOutOfMemoryStrings(const std::string& title, const std::string& message) + { + sLocalizedOutOfMemoryTitle = title; + sLocalizedOutOfMemoryWarning = message; + } } void crashdriver(void (*callback)(int*)) diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 2a8e69402b..c41e0363f7 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -39,6 +39,7 @@ #include "llpreprocessor.h" #include +#include // std::function // Disable C6011 code analyses warning for now popping up everywhere because of the LL_ENDL / LLERROR_CRASH macro #if LL_WINDOWS @@ -313,6 +314,28 @@ namespace LLError { friend std::ostream& operator<<(std::ostream& out, const LLStacktrace&); }; + + // Provides access to OS notification popup on error, since + // not everything has access to OS's messages + class LLUserWarningMsg + { + public: + typedef std::function Handler; + static void setHandler(const Handler&); + static void setOutOfMemoryStrings(const std::string& title, const std::string& message); + + // When viewer encounters bad alloc or can't access files try warning user about reasons + static void showOutOfMemory(); + static void showMissingFiles(); + // Genering error + static void show(const std::string&); + + private: + // needs to be preallocated before viewer runs out of memory + static std::string sLocalizedOutOfMemoryTitle; + static std::string sLocalizedOutOfMemoryWarning; + static Handler sHandler; + }; } //this is cheaper than llcallstacks if no need to output other variables to call stacks. diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp index 46560b5e4c..0787bde57f 100644 --- a/indra/llcommon/llexception.cpp +++ b/indra/llcommon/llexception.cpp @@ -37,6 +37,7 @@ #include "llerror.h" #include "llerrorcontrol.h" + // used to attach and extract stacktrace information to/from boost::exception, // see https://www.boost.org/doc/libs/release/doc/html/stacktrace/getting_started.html#stacktrace.getting_started.exceptions_with_stacktrace // apparently the struct passed as the first template param needs no definition? diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index f9de0c7929..64aceddf32 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -46,33 +46,32 @@ template class LLPointer { public: - - LLPointer() : + LLPointer() : mPointer(NULL) { } - LLPointer(Type* ptr) : + LLPointer(Type* ptr) : mPointer(ptr) { ref(); } - LLPointer(const LLPointer& ptr) : + LLPointer(const LLPointer& ptr) : mPointer(ptr.mPointer) { ref(); } - // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + // Support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template - LLPointer(const LLPointer& ptr) : + LLPointer(const LLPointer& ptr) : mPointer(ptr.get()) { ref(); } - ~LLPointer() + ~LLPointer() { unref(); } @@ -83,39 +82,39 @@ public: const Type& operator*() const { return *mPointer; } Type& operator*() { return *mPointer; } - operator BOOL() const { return (mPointer != NULL); } - operator bool() const { return (mPointer != NULL); } + operator BOOL() const { return (mPointer != NULL); } + operator bool() const { return (mPointer != NULL); } bool operator!() const { return (mPointer == NULL); } bool isNull() const { return (mPointer == NULL); } bool notNull() const { return (mPointer != NULL); } - 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); } + 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); } - LLPointer& operator =(Type* ptr) - { + LLPointer& operator =(Type* ptr) + { assign(ptr); - return *this; + return *this; } - LLPointer& operator =(const LLPointer& ptr) - { + LLPointer& operator =(const LLPointer& ptr) + { assign(ptr); - return *this; + return *this; } // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template - LLPointer& operator =(const LLPointer& ptr) - { + LLPointer& operator =(const LLPointer& ptr) + { assign(ptr.get()); - return *this; + return *this; } - + // Just exchange the pointers, which will not change the reference counts. static void swap(LLPointer& a, LLPointer& b) { @@ -129,16 +128,6 @@ protected: void ref(); void unref(); #else - - void assign(const LLPointer& ptr) - { - if( mPointer != ptr.mPointer ) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } - } void ref() { if (mPointer) @@ -161,7 +150,18 @@ protected: } } } -#endif +#endif // LL_LIBRARY_INCLUDE + + void assign(const LLPointer& ptr) + { + if (mPointer != ptr.mPointer) + { + unref(); + mPointer = ptr.mPointer; + ref(); + } + } + protected: Type* mPointer; }; @@ -169,18 +169,18 @@ protected: template class LLConstPointer { public: - LLConstPointer() : + LLConstPointer() : mPointer(NULL) { } - LLConstPointer(const Type* ptr) : + LLConstPointer(const Type* ptr) : mPointer(ptr) { ref(); } - LLConstPointer(const LLConstPointer& ptr) : + LLConstPointer(const LLConstPointer& ptr) : mPointer(ptr.mPointer) { ref(); @@ -188,7 +188,7 @@ public: // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template - LLConstPointer(const LLConstPointer& ptr) : + LLConstPointer(const LLConstPointer& ptr) : mPointer(ptr.get()) { ref(); @@ -203,55 +203,55 @@ public: const Type* operator->() const { return mPointer; } const Type& operator*() const { return *mPointer; } - operator BOOL() const { return (mPointer != NULL); } - operator bool() const { return (mPointer != NULL); } + operator BOOL() const { return (mPointer != NULL); } + operator bool() const { return (mPointer != NULL); } bool operator!() const { return (mPointer == NULL); } bool isNull() const { return (mPointer == NULL); } bool notNull() const { return (mPointer != NULL); } - 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); } + 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) + LLConstPointer& operator =(const Type* ptr) { if( mPointer != ptr ) { - unref(); - mPointer = ptr; + unref(); + mPointer = ptr; ref(); } - return *this; + return *this; } - LLConstPointer& operator =(const LLConstPointer& ptr) - { + LLConstPointer& operator =(const LLConstPointer& ptr) + { if( mPointer != ptr.mPointer ) { - unref(); + unref(); mPointer = ptr.mPointer; ref(); } - return *this; + return *this; } // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template - LLConstPointer& operator =(const LLConstPointer& ptr) - { + LLConstPointer& operator =(const LLConstPointer& ptr) + { if( mPointer != ptr.get() ) { - unref(); + unref(); mPointer = ptr.get(); ref(); } - return *this; + return *this; } - + // Just exchange the pointers, which will not change the reference counts. static void swap(LLConstPointer& a, LLConstPointer& b) { @@ -262,11 +262,11 @@ public: protected: #ifdef LL_LIBRARY_INCLUDE - void ref(); + void ref(); void unref(); -#else - void ref() - { +#else // LL_LIBRARY_INCLUDE + void ref() + { if (mPointer) { mPointer->ref(); @@ -277,9 +277,9 @@ protected: { if (mPointer) { - const Type *tempp = mPointer; + const Type *temp = mPointer; mPointer = NULL; - tempp->unref(); + temp->unref(); if (mPointer != NULL) { LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; @@ -287,7 +287,8 @@ protected: } } } -#endif +#endif // LL_LIBRARY_INCLUDE + protected: const Type* mPointer; }; @@ -297,13 +298,13 @@ class LLCopyOnWritePointer : public LLPointer { public: typedef LLCopyOnWritePointer self_t; - typedef LLPointer pointer_t; - - LLCopyOnWritePointer() + typedef LLPointer pointer_t; + + LLCopyOnWritePointer() : mStayUnique(false) {} - LLCopyOnWritePointer(Type* ptr) + LLCopyOnWritePointer(Type* ptr) : LLPointer(ptr), mStayUnique(false) {} diff --git a/indra/llcommon/llrand.cpp b/indra/llcommon/llrand.cpp index 33afc50cf7..0192111574 100644 --- a/indra/llcommon/llrand.cpp +++ b/indra/llcommon/llrand.cpp @@ -58,7 +58,9 @@ * to restore uniform distribution. */ -static LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed()); +// gRandomGenerator is a stateful static object, which is therefore not +// inherently thread-safe. +static thread_local LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed()); // no default implementation, only specific F64 and F32 specializations template @@ -71,7 +73,7 @@ inline F64 ll_internal_random() // CPUs (or at least multi-threaded processes) seem to // occasionally give an obviously incorrect random number -- like // 5^15 or something. Sooooo, clamp it as described above. - F64 rv = gRandomGenerator(); + F64 rv{ gRandomGenerator() }; if(!((rv >= 0.0) && (rv < 1.0))) return fmod(rv, 1.0); return rv; } @@ -79,7 +81,13 @@ inline F64 ll_internal_random() template <> inline F32 ll_internal_random() { - return F32(ll_internal_random()); + // *HACK: clamp the result as described above. + // Per Monty, it's important to clamp using the correct fmodf() rather + // than expanding to F64 for fmod() and then truncating back to F32. Prior + // to this change, we were getting sporadic ll_frand() == 1.0 results. + F32 rv{ narrow(gRandomGenerator()) }; + if(!((rv >= 0.0f) && (rv < 1.0f))) return fmodf(rv, 1.0f); + return rv; } /*------------------------------ F64 aliases -------------------------------*/ diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp index 6852b5536a..3da94e7a8d 100644 --- a/indra/llcommon/llrefcount.cpp +++ b/indra/llcommon/llrefcount.cpp @@ -30,7 +30,7 @@ #include "llerror.h" // maximum reference count before sounding memory leak alarm -const S32 gMaxRefCount = S32_MAX; +const S32 gMaxRefCount = LL_REFCOUNT_FREE; LLRefCount::LLRefCount(const LLRefCount& other) : mRef(0) @@ -49,7 +49,7 @@ LLRefCount::LLRefCount() : } LLRefCount::~LLRefCount() -{ +{ if (mRef != LL_REFCOUNT_FREE && mRef != 0) { LL_ERRS() << "deleting non-zero reference" << LL_ENDL; diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 2080da1565..15e7175fc8 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -51,24 +51,20 @@ protected: public: LLRefCount(); - inline void validateRefCount() const - { - llassert(mRef > 0); // ref count below 0, likely corrupted - llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak - } - inline void ref() const - { - mRef++; - validateRefCount(); - } + { + llassert(mRef != LL_REFCOUNT_FREE); // object is deleted + mRef++; + llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak + } inline S32 unref() const { - validateRefCount(); + llassert(mRef != LL_REFCOUNT_FREE); // object is deleted + llassert(mRef > 0); // ref count below 1, likely corrupted if (0 == --mRef) { - mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging + mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging delete this; return 0; } @@ -82,8 +78,8 @@ public: return mRef; } -private: - mutable S32 mRef; +private: + mutable S32 mRef; }; @@ -106,7 +102,7 @@ protected: public: LLThreadSafeRefCount(); LLThreadSafeRefCount(const LLThreadSafeRefCount&); - LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) + LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) { mRef = 0; return *this; @@ -114,8 +110,8 @@ public: void ref() { - mRef++; - } + mRef++; + } void unref() { @@ -136,36 +132,36 @@ public: return currentVal; } -private: - LLAtomicS32 mRef; +private: + LLAtomicS32 mRef; }; /** * intrusive pointer support for LLThreadSafeRefCount * this allows you to use boost::intrusive_ptr with any LLThreadSafeRefCount-derived type */ -inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p) +inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p) { p->ref(); } -inline void intrusive_ptr_release(LLThreadSafeRefCount* p) +inline void intrusive_ptr_release(LLThreadSafeRefCount* p) { - p->unref(); + p->unref(); } /** * intrusive pointer support * this allows you to use boost::intrusive_ptr with any LLRefCount-derived type */ -inline void intrusive_ptr_add_ref(LLRefCount* p) +inline void intrusive_ptr_add_ref(LLRefCount* p) { p->ref(); } -inline void intrusive_ptr_release(LLRefCount* p) +inline void intrusive_ptr_release(LLRefCount* p) { - p->unref(); + p->unref(); } #endif diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index cdb9a7ed8a..8ed254919c 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -197,12 +197,12 @@ public: typename std::enable_if::value && ! std::is_same::value, bool>::type = true> - LLSD(VALUE v): LLSD(Integer(narrow(v))) {} + LLSD(VALUE v): LLSD(Integer(narrow(v))) {} // support construction from F32 et al. template ::value, bool>::type = true> - LLSD(VALUE v): LLSD(Real(narrow(v))) {} + LLSD(VALUE v): LLSD(Real(narrow(v))) {} //@} /** @name Scalar Assignment */ diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 2460af381b..5a90abf38b 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -2174,7 +2174,7 @@ std::string zip_llsd(LLSD& data) U8 out[CHUNK]; - strm.avail_in = narrow(source.size()); + strm.avail_in = narrow(source.size()); strm.next_in = (U8*) source.data(); U8* output = NULL; diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 727aad3b96..584bbd07fa 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -197,12 +197,12 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, // *FIX: memory inefficient. // *TODO: convert to use LLBase64 ostr << pre << ""; - int b64_buffer_length = apr_base64_encode_len(narrow(buffer.size())); + int b64_buffer_length = apr_base64_encode_len(narrow(buffer.size())); char* b64_buffer = new char[b64_buffer_length]; b64_buffer_length = apr_base64_encode_binary( b64_buffer, &buffer[0], - narrow(buffer.size())); + narrow(buffer.size())); ostr.write(b64_buffer, b64_buffer_length - 1); delete[] b64_buffer; ostr << "" << post; @@ -415,11 +415,18 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) if (buffer) { ((char*) buffer)[count ? count - 1 : 0] = '\0'; + if (mEmitErrors) + { + LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*)buffer << LL_ENDL; + } } - if (mEmitErrors) - { - LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << LL_ENDL; - } + else + { + if (mEmitErrors) + { + LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR, null buffer" << LL_ENDL; + } + } data = LLSD(); return LLSDParser::PARSE_FAILURE; } diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index ec3c562599..034bfadeca 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -496,7 +496,7 @@ public: static DERIVED_TYPE* getInstance() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + //LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; // TODO -- reenable this when we have a fix for using Tracy with coroutines // We know the viewer has LLSingleton dependency circularities. If you // feel strongly motivated to eliminate them, cheers and good luck. // (At that point we could consider a much simpler locking mechanism.) diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 2511ca00b3..ec792ad240 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -1533,9 +1533,17 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, } else { +#if 0 + // EXT-1565 : Zai Lynch, James Linden : 15/Oct/09 + // [BSI] Feedback: Viewer clock mentions SLT, but would prefer it to show PST/PDT // "slt" = Second Life Time, which is deprecated. // If not utc or user local time, fallback to Pacific time replacement = LLStringOps::getPacificDaylightTime() ? "PDT" : "PST"; +#else + // SL-20370 : Steeltoe Linden : 29/Sep/23 + // Change "PDT" to "SLT" on menu bar + replacement = "SLT"; +#endif } return true; } diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 72825067a8..c5787b9704 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -929,7 +929,7 @@ void LLMemoryInfo::stream(std::ostream& s) const // Now stream stats BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap)) { - s << pfx << std::setw(narrow(key_width+1)) << (pair.first + ':') << ' '; + s << pfx << std::setw(narrow(key_width+1)) << (pair.first + ':') << ' '; LLSD value(pair.second); if (value.isInteger()) s << std::setw(12) << value.asInteger(); diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index fcf46c79e7..dd279614f6 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -113,15 +113,16 @@ LL_COMMON_API bool on_main_thread() return (LLThread::currentID() == main_thread()); } -LL_COMMON_API void assert_main_thread() +LL_COMMON_API bool assert_main_thread() { auto curr = LLThread::currentID(); auto main = main_thread(); - if (curr != main) - { - LL_WARNS() << "Illegal execution from thread id " << curr - << " outside main thread " << main << LL_ENDL; - } + if (curr == main) + return true; + + LL_WARNS() << "Illegal execution from thread id " << curr + << " outside main thread " << main << LL_ENDL; + return false; } // this function has become moot diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 613431ee6a..34ccbbcfe6 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -152,7 +152,7 @@ public: //============================================================================ -extern LL_COMMON_API void assert_main_thread(); +extern LL_COMMON_API bool assert_main_thread(); extern LL_COMMON_API bool on_main_thread(); #endif // LL_LLTHREAD_H diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index 082337cf3e..2a702c8d04 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -342,13 +342,7 @@ bool LLThreadSafeQueue::pushIfOpen(T&& element) return true; // Storage Full. Wait for signal. - // [FIRE-32453][BUG-232971] Improve shutdown behaviour. Time bound the sleep - // mCapacityCond.wait(lock1); - // When the queue is full and the consuming thread has exited we would never wake up. - // For safety, we now wait max half a second then recheck close. - const auto timeout = std::chrono::milliseconds(500); - mCapacityCond.wait_for(lock1, timeout); - // + mCapacityCond.wait(lock1); } } diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp index ff671a8370..87457ad907 100644 --- a/indra/llcommon/lltrace.cpp +++ b/indra/llcommon/lltrace.cpp @@ -33,8 +33,6 @@ namespace LLTrace { -MemStatHandle gTraceMemStat("LLTrace"); - StatBase::StatBase( const char* name, const char* description ) : mName(name), mDescription(description ? description : "") @@ -65,7 +63,7 @@ void TimeBlockTreeNode::setParent( BlockTimerStatHandle* parent ) llassert_always(parent != mBlock); llassert_always(parent != NULL); - TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow(parent->getIndex())); + TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow(parent->getIndex())); if (!parent_tree_node) return; if (mParent) diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index d129eae0eb..7ecb984db8 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -211,61 +211,6 @@ void add(CountStatHandle& count, VALUE_T value) #endif } -template<> -class StatType -: public StatType -{ -public: - - StatType(const char* name, const char* description = "") - : StatType(name, description) - {} -}; - -template<> -class StatType -: public StatType -{ -public: - - StatType(const char* name, const char* description = "") - : StatType(name, description) - {} -}; - -class MemStatHandle : public StatType -{ -public: - typedef StatType stat_t; - MemStatHandle(const char* name, const char* description = "") - : stat_t(name, description) - { - mName = name; - } - - void setName(const char* name) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mName = name; - setKey(name); - } - - /*virtual*/ const char* getUnitLabel() const { return "KB"; } - - StatType& allocations() - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return static_cast&>(*(StatType*)this); - } - - StatType& deallocations() - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return static_cast&>(*(StatType*)this); - } -}; - - // measures effective memory footprint of specified type // specialize to cover different types template @@ -352,33 +297,6 @@ struct MeasureMem, IS_MEM_TRACKABLE, IS_BYTES> } }; - -template -inline void claim_alloc(MemStatHandle& measurement, const T& value) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; -#if LL_TRACE_ENABLED - auto size = MeasureMem::measureFootprint(value); - if(size == 0) return; - MemAccumulator& accumulator = measurement.getCurrentAccumulator(); - accumulator.mSize.sample(accumulator.mSize.hasValue() ? accumulator.mSize.getLastValue() + (F64)size : (F64)size); - accumulator.mAllocations.record(size); -#endif -} - -template -inline void disclaim_alloc(MemStatHandle& measurement, const T& value) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; -#if LL_TRACE_ENABLED - auto size = MeasureMem::measureFootprint(value); - if(size == 0) return; - MemAccumulator& accumulator = measurement.getCurrentAccumulator(); - accumulator.mSize.sample(accumulator.mSize.hasValue() ? accumulator.mSize.getLastValue() - (F64)size : -(F64)size); - accumulator.mDeallocations.add(size); -#endif -} - } #endif // LL_LLTRACE_H diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp index 6bd886ae98..b5b32cba38 100644 --- a/indra/llcommon/lltraceaccumulators.cpp +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltracesampler.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,73 +32,52 @@ namespace LLTrace { -extern MemStatHandle gTraceMemStat; - - /////////////////////////////////////////////////////////////////////// // AccumulatorBufferGroup /////////////////////////////////////////////////////////////////////// -AccumulatorBufferGroup::AccumulatorBufferGroup() +AccumulatorBufferGroup::AccumulatorBufferGroup() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator)); - claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator)); - claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator)); - claim_alloc(gTraceMemStat, mStackTimers.capacity() * sizeof(TimeBlockAccumulator)); - claim_alloc(gTraceMemStat, mMemStats.capacity() * sizeof(MemAccumulator)); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& other) : mCounts(other.mCounts), mSamples(other.mSamples), mEvents(other.mEvents), - mStackTimers(other.mStackTimers), - mMemStats(other.mMemStats) + mStackTimers(other.mStackTimers) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator)); - claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator)); - claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator)); - claim_alloc(gTraceMemStat, mStackTimers.capacity() * sizeof(TimeBlockAccumulator)); - claim_alloc(gTraceMemStat, mMemStats.capacity() * sizeof(MemAccumulator)); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } AccumulatorBufferGroup::~AccumulatorBufferGroup() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - disclaim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator)); - disclaim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator)); - disclaim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator)); - disclaim_alloc(gTraceMemStat, mStackTimers.capacity() * sizeof(TimeBlockAccumulator)); - disclaim_alloc(gTraceMemStat, mMemStats.capacity() * sizeof(MemAccumulator)); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; other.mCounts.reset(&mCounts); other.mSamples.reset(&mSamples); other.mEvents.reset(&mEvents); other.mStackTimers.reset(&mStackTimers); - other.mMemStats.reset(&mMemStats); } void AccumulatorBufferGroup::makeCurrent() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mCounts.makeCurrent(); mSamples.makeCurrent(); mEvents.makeCurrent(); mStackTimers.makeCurrent(); - mMemStats.makeCurrent(); ThreadRecorder* thread_recorder = get_thread_recorder(); AccumulatorBuffer& timer_accumulator_buffer = mStackTimers; // update stacktimer parent pointers for (size_t i = 0, end_i = mStackTimers.size(); i < end_i; i++) { - TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow(i)); + TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow(i)); if (tree_node) { timer_accumulator_buffer[i].mParent = tree_node->mParent; @@ -109,12 +88,11 @@ void AccumulatorBufferGroup::makeCurrent() //static void AccumulatorBufferGroup::clearCurrent() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - AccumulatorBuffer::clearCurrent(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + AccumulatorBuffer::clearCurrent(); AccumulatorBuffer::clearCurrent(); AccumulatorBuffer::clearCurrent(); AccumulatorBuffer::clearCurrent(); - AccumulatorBuffer::clearCurrent(); } bool AccumulatorBufferGroup::isCurrent() const @@ -124,44 +102,39 @@ bool AccumulatorBufferGroup::isCurrent() const void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mCounts.addSamples(other.mCounts, SEQUENTIAL); mSamples.addSamples(other.mSamples, SEQUENTIAL); mEvents.addSamples(other.mEvents, SEQUENTIAL); - mMemStats.addSamples(other.mMemStats, SEQUENTIAL); mStackTimers.addSamples(other.mStackTimers, SEQUENTIAL); } void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mCounts.addSamples(other.mCounts, NON_SEQUENTIAL); mSamples.addSamples(other.mSamples, NON_SEQUENTIAL); mEvents.addSamples(other.mEvents, NON_SEQUENTIAL); - mMemStats.addSamples(other.mMemStats, NON_SEQUENTIAL); // for now, hold out timers from merge, need to be displayed per thread //mStackTimers.addSamples(other.mStackTimers, NON_SEQUENTIAL); } void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mCounts.reset(other ? &other->mCounts : NULL); mSamples.reset(other ? &other->mSamples : NULL); mEvents.reset(other ? &other->mEvents : NULL); mStackTimers.reset(other ? &other->mStackTimers : NULL); - mMemStats.reset(other ? &other->mMemStats : NULL); } void AccumulatorBufferGroup::sync() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (isCurrent()) { F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); - mSamples.sync(time_stamp); - mMemStats.sync(time_stamp); } } @@ -197,10 +170,9 @@ F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const Samp return a.getSumOfSquares(); } - void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type ) { - if (append_type == NON_SEQUENTIAL) + if (append_type == NON_SEQUENTIAL) { return; } @@ -299,7 +271,7 @@ void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendT void EventAccumulator::reset( const EventAccumulator* other ) { - mNumSamples = 0; + mNumSamples = 0; mSum = 0; mMin = F32(NaN); mMax = F32(NaN); @@ -308,5 +280,4 @@ void EventAccumulator::reset( const EventAccumulator* other ) mLastValue = other ? other->mLastValue : NaN; } - } diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h index 7267a44300..b9d577be9e 100644 --- a/indra/llcommon/lltraceaccumulators.h +++ b/indra/llcommon/lltraceaccumulators.h @@ -1,26 +1,26 @@ -/** +/** * @file lltraceaccumulators.h * @brief Storage for accumulating statistics * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,7 +28,6 @@ #ifndef LL_LLTRACEACCUMULATORS_H #define LL_LLTRACEACCUMULATORS_H - #include "stdtypes.h" #include "llpreprocessor.h" #include "llunits.h" @@ -66,7 +65,7 @@ namespace LLTrace : mStorageSize(0), mStorage(NULL) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; const AccumulatorBuffer& other = *getDefaultBuffer(); resize(sNextStorageSlot); for (S32 i = 0; i < sNextStorageSlot; i++) @@ -77,7 +76,7 @@ namespace LLTrace ~AccumulatorBuffer() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (isCurrent()) { LLThreadLocalSingletonPointer::setInstance(NULL); @@ -85,14 +84,14 @@ namespace LLTrace delete[] mStorage; } - LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index) - { - return mStorage[index]; + LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index) + { + return mStorage[index]; } LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const - { - return mStorage[index]; + { + return mStorage[index]; } @@ -100,7 +99,7 @@ namespace LLTrace : mStorageSize(0), mStorage(NULL) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; resize(sNextStorageSlot); for (S32 i = 0; i < sNextStorageSlot; i++) { @@ -110,7 +109,7 @@ namespace LLTrace void addSamples(const AccumulatorBuffer& other, EBufferAppendType append_type) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); for (size_t i = 0; i < sNextStorageSlot; i++) { @@ -120,7 +119,7 @@ namespace LLTrace void copyFrom(const AccumulatorBuffer& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); for (size_t i = 0; i < sNextStorageSlot; i++) { @@ -130,7 +129,7 @@ namespace LLTrace void reset(const AccumulatorBuffer* other = NULL) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; llassert(mStorageSize >= sNextStorageSlot); for (size_t i = 0; i < sNextStorageSlot; i++) { @@ -140,7 +139,7 @@ namespace LLTrace void sync(F64SecondsImplicit time_stamp) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; llassert(mStorageSize >= sNextStorageSlot); for (size_t i = 0; i < sNextStorageSlot; i++) { @@ -160,13 +159,13 @@ namespace LLTrace static void clearCurrent() { - LLThreadLocalSingletonPointer::setInstance(NULL); + LLThreadLocalSingletonPointer::setInstance(NULL); } // NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned size_t reserveSlot() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; size_t next_slot = sNextStorageSlot++; if (next_slot >= mStorageSize) { @@ -180,7 +179,7 @@ namespace LLTrace void resize(size_t new_size) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (new_size <= mStorageSize) return; ACCUMULATOR* old_storage = mStorage; @@ -214,14 +213,14 @@ namespace LLTrace return mStorageSize; } - static size_t getNumIndices() + static size_t getNumIndices() { return sNextStorageSlot; } static self_t* getDefaultBuffer() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; static bool sInitialized = false; if (!sInitialized) { @@ -336,7 +335,7 @@ namespace LLTrace void sample(F64 value) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); // store effect of last value @@ -399,7 +398,7 @@ namespace LLTrace F64 mMean, mSumOfSquares; - F64SecondsImplicit + F64SecondsImplicit mLastSampleTimeStamp, mTotalSamplingTime; @@ -409,7 +408,7 @@ namespace LLTrace S32 mNumSamples; // distinct from mNumSamples, since we might have inherited a last value from // a previous sampling period - bool mHasValue; + bool mHasValue; }; class CountAccumulator @@ -457,14 +456,14 @@ namespace LLTrace class alignas(32) TimeBlockAccumulator { - public: + public: typedef F64Seconds value_t; static F64Seconds getDefaultValue() { return F64Seconds(0); } typedef TimeBlockAccumulator self_t; // fake classes that allows us to view different facets of underlying statistic - struct CallCountFacet + struct CallCountFacet { typedef S32 value_t; }; @@ -515,12 +514,12 @@ namespace LLTrace BlockTimerStatHandle* getParent() { return mParent; } BlockTimerStatHandle* mBlock; - BlockTimerStatHandle* mParent; + BlockTimerStatHandle* mParent; std::vector mChildren; bool mCollapsed; bool mNeedsSorting; }; - + struct BlockTimerStackRecord { class BlockTimer* mActiveTimer; @@ -528,65 +527,6 @@ namespace LLTrace U64 mChildTime; }; - struct MemAccumulator - { - typedef F64Bytes value_t; - static F64Bytes getDefaultValue() { return F64Bytes(0); } - - typedef MemAccumulator self_t; - - // fake classes that allows us to view different facets of underlying statistic - struct AllocationFacet - { - typedef F64Bytes value_t; - static F64Bytes getDefaultValue() { return F64Bytes(0); } - }; - - struct DeallocationFacet - { - typedef F64Bytes value_t; - static F64Bytes getDefaultValue() { return F64Bytes(0); } - }; - - void addSamples(const MemAccumulator& other, EBufferAppendType append_type) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mAllocations.addSamples(other.mAllocations, append_type); - mDeallocations.addSamples(other.mDeallocations, append_type); - - if (append_type == SEQUENTIAL) - { - mSize.addSamples(other.mSize, SEQUENTIAL); - } - else - { - F64 allocation_delta(other.mAllocations.getSum() - other.mDeallocations.getSum()); - mSize.sample(mSize.hasValue() - ? mSize.getLastValue() + allocation_delta - : allocation_delta); - } - } - - void reset(const MemAccumulator* other) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mSize.reset(other ? &other->mSize : NULL); - mAllocations.reset(other ? &other->mAllocations : NULL); - mDeallocations.reset(other ? &other->mDeallocations : NULL); - } - - void sync(F64SecondsImplicit time_stamp) - { - mSize.sync(time_stamp); - } - - bool hasValue() const { return mSize.hasValue(); } - - SampleAccumulator mSize; - EventAccumulator mAllocations; - CountAccumulator mDeallocations; - }; - struct AccumulatorBufferGroup : public LLRefCount { AccumulatorBufferGroup(); @@ -607,9 +547,7 @@ namespace LLTrace AccumulatorBuffer mSamples; AccumulatorBuffer mEvents; AccumulatorBuffer mStackTimers; - AccumulatorBuffer mMemStats; }; } #endif // LL_LLTRACEACCUMULATORS_H - diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index bb3d667a42..075e7c1d28 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltracesampler.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,7 +32,7 @@ #include "lltracethreadrecorder.h" #include "llthread.h" -inline F64 lerp(F64 a, F64 b, F64 u) +inline F64 lerp(F64 a, F64 b, F64 u) { return a + ((b - a) * u); } @@ -40,34 +40,29 @@ inline F64 lerp(F64 a, F64 b, F64 u) namespace LLTrace { -extern MemStatHandle gTraceMemStat; - /////////////////////////////////////////////////////////////////////// // Recording /////////////////////////////////////////////////////////////////////// -Recording::Recording(EPlayState state) +Recording::Recording(EPlayState state) : mElapsedSeconds(0), mActiveBuffers(NULL) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - claim_alloc(gTraceMemStat, this); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mBuffers = new AccumulatorBufferGroup(); - claim_alloc(gTraceMemStat, mBuffers); setPlayState(state); } Recording::Recording( const Recording& other ) : mActiveBuffers(NULL) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - claim_alloc(gTraceMemStat, this); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; *this = other; } Recording& Recording::operator = (const Recording& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; // this will allow us to seamlessly start without affecting any data we've acquired from other setPlayState(PAUSED); @@ -85,14 +80,11 @@ Recording& Recording::operator = (const Recording& other) return *this; } - Recording::~Recording() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - disclaim_alloc(gTraceMemStat, this); - disclaim_alloc(gTraceMemStat, mBuffers); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - // allow recording destruction without thread recorder running, + // allow recording destruction without thread recorder running, // otherwise thread shutdown could crash if a recording outlives the thread recorder // besides, recording construction and destruction is fine without a recorder...just don't attempt to start one if (isStarted() && LLTrace::get_thread_recorder() != NULL) @@ -107,14 +99,14 @@ void Recording::update() #if LL_TRACE_ENABLED if (isStarted()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); - // must have - llassert(mActiveBuffers != NULL + // must have + llassert(mActiveBuffers != NULL && LLTrace::get_thread_recorder() != NULL); - if(!mActiveBuffers->isCurrent() && LLTrace::get_thread_recorder() != NULL) + if (!mActiveBuffers->isCurrent() && LLTrace::get_thread_recorder() != NULL) { AccumulatorBufferGroup* buffers = mBuffers.write(); LLTrace::get_thread_recorder()->deactivate(buffers); @@ -128,7 +120,7 @@ void Recording::update() void Recording::handleReset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED mBuffers.write()->reset(); @@ -139,7 +131,7 @@ void Recording::handleReset() void Recording::handleStart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED mSamplingTimer.reset(); mBuffers.setStayUnique(true); @@ -151,7 +143,7 @@ void Recording::handleStart() void Recording::handleStop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); // must have thread recorder running on this thread @@ -204,7 +196,6 @@ F64Seconds Recording::getSum(const StatType return F64Seconds(((F64)(accumulator.mSelfTimeCounter) + (F64)(active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) / (F64)LLTrace::BlockTimer::countsPerSecond()); } - S32 Recording::getSum(const StatType& stat) { update(); @@ -219,7 +210,7 @@ F64Seconds Recording::getPerSec(const StatType& stat) const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return F64Seconds((F64)(accumulator.mTotalTimeCounter + (active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) + return F64Seconds((F64)(accumulator.mTotalTimeCounter + (active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value())); } @@ -241,144 +232,9 @@ F32 Recording::getPerSec(const StatType& s return (F32)(accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0)) / mElapsedSeconds.value(); } -bool Recording::hasValue(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return accumulator.mSize.hasValue() || (active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.hasValue() : false); -} - -F64Kilobytes Recording::getMin(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return F64Bytes(llmin(accumulator.mSize.getMin(), (active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMin() : F32_MAX))); -} - -F64Kilobytes Recording::getMean(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - - if (active_accumulator && active_accumulator->mSize.hasValue()) - { - F32 t = 0.0f; - S32 div = accumulator.mSize.getSampleCount() + active_accumulator->mSize.getSampleCount(); - if (div > 0) - { - t = active_accumulator->mSize.getSampleCount() / div; - } - return F64Bytes(lerp(accumulator.mSize.getMean(), active_accumulator->mSize.getMean(), t)); - } - else - { - return F64Bytes(accumulator.mSize.getMean()); - } -} - -F64Kilobytes Recording::getMax(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return F64Bytes(llmax(accumulator.mSize.getMax(), active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMax() : F32_MIN)); -} - -F64Kilobytes Recording::getStandardDeviation(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - if (active_accumulator && active_accumulator->hasValue()) - { - F64 sum_of_squares = SampleAccumulator::mergeSumsOfSquares(accumulator.mSize, active_accumulator->mSize); - return F64Bytes(sqrtf(sum_of_squares / (accumulator.mSize.getSamplingTime().value() + active_accumulator->mSize.getSamplingTime().value()))); - } - else - { - return F64Bytes(accumulator.mSize.getStandardDeviation()); - } -} - -F64Kilobytes Recording::getLastValue(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return F64Bytes(active_accumulator ? active_accumulator->mSize.getLastValue() : accumulator.mSize.getLastValue()); -} - -bool Recording::hasValue(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return accumulator.mAllocations.hasValue() || (active_accumulator ? active_accumulator->mAllocations.hasValue() : false); -} - -F64Kilobytes Recording::getSum(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return F64Bytes(accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)); -} - -F64Kilobytes Recording::getPerSec(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return F64Bytes((accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)) / mElapsedSeconds.value()); -} - -S32 Recording::getSampleCount(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return accumulator.mAllocations.getSampleCount() + (active_accumulator ? active_accumulator->mAllocations.getSampleCount() : 0); -} - -bool Recording::hasValue(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return accumulator.mDeallocations.hasValue() || (active_accumulator ? active_accumulator->mDeallocations.hasValue() : false); -} - - -F64Kilobytes Recording::getSum(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return F64Bytes(accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)); -} - -F64Kilobytes Recording::getPerSec(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return F64Bytes((accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)) / mElapsedSeconds.value()); -} - -S32 Recording::getSampleCount(const StatType& stat) -{ - update(); - const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; - const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; - return accumulator.mDeallocations.getSampleCount() + (active_accumulator ? active_accumulator->mDeallocations.getSampleCount() : 0); -} - bool Recording::hasValue(const StatType& stat) { - update(); + update(); const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false); @@ -386,7 +242,7 @@ bool Recording::hasValue(const StatType& stat) F64 Recording::getSum(const StatType& stat) { - update(); + update(); const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); @@ -394,7 +250,7 @@ F64 Recording::getSum(const StatType& stat) F64 Recording::getPerSec( const StatType& stat ) { - update(); + update(); const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); @@ -403,7 +259,7 @@ F64 Recording::getPerSec( const StatType& stat ) S32 Recording::getSampleCount( const StatType& stat ) { - update(); + update(); const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); @@ -411,7 +267,7 @@ S32 Recording::getSampleCount( const StatType& stat ) bool Recording::hasValue(const StatType& stat) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); @@ -419,7 +275,7 @@ bool Recording::hasValue(const StatType& stat) F64 Recording::getMin( const StatType& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); @@ -427,7 +283,7 @@ F64 Recording::getMin( const StatType& stat ) F64 Recording::getMax( const StatType& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); @@ -435,17 +291,17 @@ F64 Recording::getMax( const StatType& stat ) F64 Recording::getMean( const StatType& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; if (active_accumulator && active_accumulator->hasValue()) { - F32 t = 0.0f; - S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); - if (div > 0) - { - t = active_accumulator->getSampleCount() / div; - } + F32 t = 0.0f; + S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); + if (div > 0) + { + t = active_accumulator->getSampleCount() / div; + } return lerp(accumulator.getMean(), active_accumulator->getMean(), t); } else @@ -456,7 +312,7 @@ F64 Recording::getMean( const StatType& stat ) F64 Recording::getStandardDeviation( const StatType& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; @@ -473,7 +329,7 @@ F64 Recording::getStandardDeviation( const StatType& stat ) F64 Recording::getLastValue( const StatType& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue()); @@ -481,7 +337,7 @@ F64 Recording::getLastValue( const StatType& stat ) S32 Recording::getSampleCount( const StatType& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0); @@ -489,7 +345,7 @@ S32 Recording::getSampleCount( const StatType& stat ) bool Recording::hasValue(const StatType& stat) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); @@ -497,7 +353,7 @@ bool Recording::hasValue(const StatType& stat) F64 Recording::getSum( const StatType& stat) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0)); @@ -505,7 +361,7 @@ F64 Recording::getSum( const StatType& stat) F64 Recording::getMin( const StatType& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); @@ -513,7 +369,7 @@ F64 Recording::getMin( const StatType& stat ) F64 Recording::getMax( const StatType& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); @@ -521,17 +377,17 @@ F64 Recording::getMax( const StatType& stat ) F64 Recording::getMean( const StatType& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; if (active_accumulator && active_accumulator->hasValue()) { F32 t = 0.0f; - S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); - if (div > 0) - { - t = active_accumulator->getSampleCount() / div; - } + S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); + if (div > 0) + { + t = active_accumulator->getSampleCount() / div; + } return lerp(accumulator.getMean(), active_accumulator->getMean(), t); } else @@ -542,7 +398,7 @@ F64 Recording::getMean( const StatType& stat ) F64 Recording::getStandardDeviation( const StatType& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; @@ -559,7 +415,7 @@ F64 Recording::getStandardDeviation( const StatType& stat ) F64 Recording::getLastValue( const StatType& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue(); @@ -567,7 +423,7 @@ F64 Recording::getLastValue( const StatType& stat ) S32 Recording::getSampleCount( const StatType& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); @@ -577,7 +433,7 @@ S32 Recording::getSampleCount( const StatType& stat ) // PeriodicRecording /////////////////////////////////////////////////////////////////////// -PeriodicRecording::PeriodicRecording( size_t num_periods, EPlayState state) +PeriodicRecording::PeriodicRecording( size_t num_periods, EPlayState state) : mAutoResize(num_periods == 0), mCurPeriod(0), mNumRecordedPeriods(0), @@ -585,15 +441,13 @@ PeriodicRecording::PeriodicRecording( size_t num_periods, EPlayState state) // code in several methods. mRecordingPeriods(num_periods ? num_periods : 1) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; setPlayState(state); - claim_alloc(gTraceMemStat, this); } PeriodicRecording::~PeriodicRecording() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - disclaim_alloc(gTraceMemStat, this); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } void PeriodicRecording::nextPeriod() @@ -615,12 +469,11 @@ void PeriodicRecording::nextPeriod() void PeriodicRecording::appendRecording(Recording& recording) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; getCurRecording().appendRecording(recording); nextPeriod(); } - void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; @@ -693,16 +546,14 @@ F64Seconds PeriodicRecording::getDuration() const return duration; } - LLTrace::Recording PeriodicRecording::snapshotCurRecording() const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; Recording recording_copy(getCurRecording()); recording_copy.stop(); return recording_copy; } - Recording& PeriodicRecording::getLastRecording() { return getPrevRecording(1); @@ -737,19 +588,19 @@ const Recording& PeriodicRecording::getPrevRecording( size_t offset ) const void PeriodicRecording::handleStart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; getCurRecording().start(); } void PeriodicRecording::handleStop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; getCurRecording().pause(); } void PeriodicRecording::handleReset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; getCurRecording().stop(); if (mAutoResize) @@ -771,13 +622,13 @@ void PeriodicRecording::handleReset() void PeriodicRecording::handleSplitTo(PeriodicRecording& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; getCurRecording().splitTo(other.getCurRecording()); } F64 PeriodicRecording::getPeriodMin( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -792,14 +643,14 @@ F64 PeriodicRecording::getPeriodMin( const StatType& stat, siz } } - return has_value - ? min_val + return has_value + ? min_val : NaN; } F64 PeriodicRecording::getPeriodMax( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -814,15 +665,15 @@ F64 PeriodicRecording::getPeriodMax( const StatType& stat, siz } } - return has_value - ? max_val + return has_value + ? max_val : NaN; } // calculates means using aggregates per period F64 PeriodicRecording::getPeriodMean( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64 mean = 0; @@ -838,14 +689,14 @@ F64 PeriodicRecording::getPeriodMean( const StatType& stat, si } } - return valid_period_count + return valid_period_count ? mean / (F64)valid_period_count : NaN; } F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64 period_mean = getPeriodMean(stat, num_periods); @@ -870,7 +721,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -885,14 +736,14 @@ F64 PeriodicRecording::getPeriodMin( const StatType& stat, si } } - return has_value - ? min_val + return has_value + ? min_val : NaN; } F64 PeriodicRecording::getPeriodMax(const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -907,15 +758,15 @@ F64 PeriodicRecording::getPeriodMax(const StatType& stat, siz } } - return has_value - ? max_val + return has_value + ? max_val : NaN; } F64 PeriodicRecording::getPeriodMean( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); S32 valid_period_count = 0; @@ -938,7 +789,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType& stat, s F64 PeriodicRecording::getPeriodMedian( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); std::vector buf; @@ -964,7 +815,7 @@ F64 PeriodicRecording::getPeriodMedian( const StatType& stat, F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64 period_mean = getPeriodMean(stat, num_periods); @@ -987,105 +838,13 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - F64Kilobytes min_val(std::numeric_limits::max()); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - min_val = llmin(min_val, recording.getMin(stat)); - } - - return min_val; -} - -F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, size_t num_periods) -{ - return getPeriodMin(static_cast&>(stat), num_periods); -} - -F64Kilobytes PeriodicRecording::getPeriodMax(const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - F64Kilobytes max_val(0.0); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - max_val = llmax(max_val, recording.getMax(stat)); - } - - return max_val; -} - -F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, size_t num_periods) -{ - return getPeriodMax(static_cast&>(stat), num_periods); -} - -F64Kilobytes PeriodicRecording::getPeriodMean( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - F64Kilobytes mean(0); - - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - mean += recording.getMean(stat); - } - - return mean / F64(num_periods); -} - -F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, size_t num_periods) -{ - return getPeriodMean(static_cast&>(stat), num_periods); -} - -F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - F64Kilobytes period_mean = getPeriodMean(stat, num_periods); - S32 valid_period_count = 0; - F64 sum_of_squares = 0; - - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - F64Kilobytes delta = recording.getMean(stat) - period_mean; - sum_of_squares += delta.value() * delta.value(); - valid_period_count++; - } - } - - return F64Kilobytes(valid_period_count - ? sqrt(sum_of_squares / (F64)valid_period_count) - : NaN); -} - -F64Kilobytes PeriodicRecording::getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods) -{ - return getPeriodStandardDeviation(static_cast&>(stat), num_periods); -} - /////////////////////////////////////////////////////////////////////// // ExtendableRecording /////////////////////////////////////////////////////////////////////// void ExtendableRecording::extend() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; // push the data back to accepted recording mAcceptedRecording.appendRecording(mPotentialRecording); // flush data, so we can start from scratch @@ -1094,76 +853,72 @@ void ExtendableRecording::extend() void ExtendableRecording::handleStart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.start(); } void ExtendableRecording::handleStop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.pause(); } void ExtendableRecording::handleReset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mAcceptedRecording.reset(); mPotentialRecording.reset(); } void ExtendableRecording::handleSplitTo(ExtendableRecording& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.splitTo(other.mPotentialRecording); } - /////////////////////////////////////////////////////////////////////// // ExtendablePeriodicRecording /////////////////////////////////////////////////////////////////////// - -ExtendablePeriodicRecording::ExtendablePeriodicRecording() -: mAcceptedRecording(0), +ExtendablePeriodicRecording::ExtendablePeriodicRecording() +: mAcceptedRecording(0), mPotentialRecording(0) {} void ExtendablePeriodicRecording::extend() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; // push the data back to accepted recording mAcceptedRecording.appendPeriodicRecording(mPotentialRecording); // flush data, so we can start from scratch mPotentialRecording.reset(); } - void ExtendablePeriodicRecording::handleStart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.start(); } void ExtendablePeriodicRecording::handleStop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.pause(); } void ExtendablePeriodicRecording::handleReset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mAcceptedRecording.reset(); mPotentialRecording.reset(); } void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.splitTo(other.mPotentialRecording); } - PeriodicRecording& get_frame_recording() { static thread_local PeriodicRecording sRecording(200, PeriodicRecording::STARTED); @@ -1174,7 +929,7 @@ PeriodicRecording& get_frame_recording() void LLStopWatchControlsMixinCommon::start() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1196,7 +951,7 @@ void LLStopWatchControlsMixinCommon::start() void LLStopWatchControlsMixinCommon::stop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1216,7 +971,7 @@ void LLStopWatchControlsMixinCommon::stop() void LLStopWatchControlsMixinCommon::pause() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1236,7 +991,7 @@ void LLStopWatchControlsMixinCommon::pause() void LLStopWatchControlsMixinCommon::unpause() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1256,7 +1011,7 @@ void LLStopWatchControlsMixinCommon::unpause() void LLStopWatchControlsMixinCommon::resume() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1277,7 +1032,7 @@ void LLStopWatchControlsMixinCommon::resume() void LLStopWatchControlsMixinCommon::restart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1301,13 +1056,13 @@ void LLStopWatchControlsMixinCommon::restart() void LLStopWatchControlsMixinCommon::reset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; handleReset(); } void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch(state) { case STOPPED: diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index a6b1a67d02..61b9096ae2 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -1,25 +1,25 @@ -/** +/** * @file lltracerecording.h * @brief Sampling object for collecting runtime statistics originating from lltrace. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -112,7 +112,6 @@ private: // atomically stop this object while starting the other // no data can be missed in between stop and start virtual void handleSplitTo(DERIVED& other) {}; - }; namespace LLTrace @@ -129,8 +128,6 @@ namespace LLTrace template class EventStatHandle; - class MemStatHandle; - template struct RelatedTypes { @@ -152,7 +149,7 @@ namespace LLTrace typedef S32 sum_t; }; - class Recording + class Recording : public LLStopWatchControlsMixin { public: @@ -182,24 +179,6 @@ namespace LLTrace F64Seconds getPerSec(const StatType& stat); F32 getPerSec(const StatType& stat); - // Memory accessors - bool hasValue(const StatType& stat); - F64Kilobytes getMin(const StatType& stat); - F64Kilobytes getMean(const StatType& stat); - F64Kilobytes getMax(const StatType& stat); - F64Kilobytes getStandardDeviation(const StatType& stat); - F64Kilobytes getLastValue(const StatType& stat); - - bool hasValue(const StatType& stat); - F64Kilobytes getSum(const StatType& stat); - F64Kilobytes getPerSec(const StatType& stat); - S32 getSampleCount(const StatType& stat); - - bool hasValue(const StatType& stat); - F64Kilobytes getSum(const StatType& stat); - F64Kilobytes getPerSec(const StatType& stat); - S32 getSampleCount(const StatType& stat); - // CountStatHandle accessors bool hasValue(const StatType& stat); F64 getSum(const StatType& stat); @@ -318,7 +297,7 @@ namespace LLTrace /*virtual*/ void handleSplitTo(Recording& other); // returns data for current thread - class ThreadRecorder* getThreadRecorder(); + class ThreadRecorder* getThreadRecorder(); LLTimer mSamplingTimer; F64Seconds mElapsedSeconds; @@ -335,10 +314,10 @@ namespace LLTrace ~PeriodicRecording(); void nextPeriod(); - auto getNumRecordedPeriods() - { + auto getNumRecordedPeriods() + { // current period counts if not active - return mNumRecordedPeriods + (isStarted() ? 0 : 1); + return mNumRecordedPeriods + (isStarted() ? 0 : 1); } F64Seconds getDuration() const; @@ -367,7 +346,7 @@ namespace LLTrace } return num_samples; } - + // // PERIODIC MIN // @@ -376,7 +355,7 @@ namespace LLTrace template typename T::value_t getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -391,15 +370,15 @@ namespace LLTrace } } - return has_value - ? min_val + return has_value + ? min_val : T::getDefaultValue(); } template T getPeriodMin(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMin(static_cast&>(stat), num_periods)); } @@ -407,7 +386,7 @@ namespace LLTrace template T getPeriodMin(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMin(static_cast&>(stat), num_periods)); } @@ -415,17 +394,14 @@ namespace LLTrace template T getPeriodMin(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMin(static_cast&>(stat), num_periods)); } - F64Kilobytes getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - F64Kilobytes getPeriodMin(const MemStatHandle& stat, size_t num_periods = std::numeric_limits::max()); - template typename RelatedTypes::fractional_t getPeriodMinPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); typename RelatedTypes::fractional_t min_val(std::numeric_limits::max()); @@ -440,7 +416,7 @@ namespace LLTrace template typename RelatedTypes::fractional_t getPeriodMinPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMinPerSec(static_cast&>(stat), num_periods)); } @@ -452,7 +428,7 @@ namespace LLTrace template typename T::value_t getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -467,15 +443,15 @@ namespace LLTrace } } - return has_value - ? max_val + return has_value + ? max_val : T::getDefaultValue(); } template T getPeriodMax(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMax(static_cast&>(stat), num_periods)); } @@ -483,7 +459,7 @@ namespace LLTrace template T getPeriodMax(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMax(static_cast&>(stat), num_periods)); } @@ -491,17 +467,14 @@ namespace LLTrace template T getPeriodMax(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMax(static_cast&>(stat), num_periods)); } - F64Kilobytes getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - F64Kilobytes getPeriodMax(const MemStatHandle& stat, size_t num_periods = std::numeric_limits::max()); - template typename RelatedTypes::fractional_t getPeriodMaxPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64 max_val = std::numeric_limits::min(); @@ -516,7 +489,7 @@ namespace LLTrace template typename RelatedTypes::fractional_t getPeriodMaxPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMaxPerSec(static_cast&>(stat), num_periods)); } @@ -528,7 +501,7 @@ namespace LLTrace template typename RelatedTypes::fractional_t getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); typename RelatedTypes::fractional_t mean(0); @@ -549,14 +522,14 @@ namespace LLTrace template typename RelatedTypes::fractional_t getPeriodMean(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); } F64 getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - template + template typename RelatedTypes::fractional_t getPeriodMean(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); } @@ -564,17 +537,14 @@ namespace LLTrace template typename RelatedTypes::fractional_t getPeriodMean(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); } - F64Kilobytes getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - F64Kilobytes getPeriodMean(const MemStatHandle& stat, size_t num_periods = std::numeric_limits::max()); - template typename RelatedTypes::fractional_t getPeriodMeanPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); typename RelatedTypes::fractional_t mean = 0; @@ -596,7 +566,7 @@ namespace LLTrace template typename RelatedTypes::fractional_t getPeriodMeanPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMeanPerSec(static_cast&>(stat), num_periods)); } @@ -635,10 +605,10 @@ namespace LLTrace F64 getPeriodStandardDeviation(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - template + template typename RelatedTypes::fractional_t getPeriodStandardDeviation(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodStandardDeviation(static_cast&>(stat), num_periods)); } @@ -646,13 +616,10 @@ namespace LLTrace template typename RelatedTypes::fractional_t getPeriodStandardDeviation(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodStandardDeviation(static_cast&>(stat), num_periods)); } - F64Kilobytes getPeriodStandardDeviation(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods = std::numeric_limits::max()); - private: // implementation for LLStopWatchControlsMixin /*virtual*/ void handleStart(); @@ -731,7 +698,7 @@ namespace LLTrace PeriodicRecording& getResults() { return mAcceptedRecording; } const PeriodicRecording& getResults() const {return mAcceptedRecording;} - + void nextPeriod() { mPotentialRecording.nextPeriod(); } private: diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index 282c454a2a..914bfb55dc 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -32,7 +32,7 @@ namespace LLTrace { -extern MemStatHandle gTraceMemStat; +//extern MemStatHandle gTraceMemStat; static ThreadRecorder* sMasterThreadRecorder = NULL; @@ -81,9 +81,9 @@ void ThreadRecorder::init() BlockTimer::getRootTimeBlock().getCurrentAccumulator().mActiveCount = 1; - claim_alloc(gTraceMemStat, this); - claim_alloc(gTraceMemStat, mRootTimer); - claim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); + //claim_alloc(gTraceMemStat, this); + //claim_alloc(gTraceMemStat, mRootTimer); + //claim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); #endif } @@ -101,9 +101,9 @@ ThreadRecorder::~ThreadRecorder() #if LL_TRACE_ENABLED LLThreadLocalSingletonPointer::setInstance(NULL); - disclaim_alloc(gTraceMemStat, this); - disclaim_alloc(gTraceMemStat, sizeof(BlockTimer)); - disclaim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); + //disclaim_alloc(gTraceMemStat, this); + //disclaim_alloc(gTraceMemStat, sizeof(BlockTimer)); + //disclaim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); deactivate(&mThreadRecordingBuffers); diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp index e4f229dd16..f79a98a56d 100644 --- a/indra/llcommon/lluriparser.cpp +++ b/indra/llcommon/lluriparser.cpp @@ -164,8 +164,10 @@ void LLUriParser::extractParts() #if LL_DARWIN typedef void(*sighandler_t)(int); jmp_buf return_to_normalize; +static int sLastSignal = 0; void uri_signal_handler(int signal) { + sLastSignal = signal; // Apparently signal handler throwing an exception doesn't work. // This is ugly and unsafe due to not unwinding content of uriparser library, // but unless we have a way to catch this as NSexception, jump appears to be the only option. @@ -179,8 +181,10 @@ S32 LLUriParser::normalize() if (!mRes) { #if LL_DARWIN - sighandler_t last_handler; - last_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction + sighandler_t last_sigill_handler, last_sigbus_handler; + last_sigill_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction + last_sigbus_handler = signal(SIGBUS, &uri_signal_handler); + if (setjmp(return_to_normalize)) { // Issue: external library crashed via signal @@ -194,8 +198,9 @@ S32 LLUriParser::normalize() // if this can be handled by NSexception, it needs to be remade llassert(0); - LL_WARNS() << "Uriparser crashed with SIGILL, while processing: " << mNormalizedUri << LL_ENDL; - signal(SIGILL, last_handler); + LL_WARNS() << "Uriparser crashed with " << sLastSignal << " , while processing: " << mNormalizedUri << LL_ENDL; + signal(SIGILL, last_sigill_handler); + signal(SIGBUS, last_sigbus_handler); return 1; } #endif @@ -203,7 +208,8 @@ S32 LLUriParser::normalize() mRes = uriNormalizeSyntaxExA(&mUri, URI_NORMALIZE_SCHEME | URI_NORMALIZE_HOST); #if LL_DARWIN - signal(SIGILL, last_handler); + signal(SIGILL, last_sigill_handler); + signal(SIGBUS, last_sigbus_handler); #endif if (!mRes) @@ -226,7 +232,7 @@ S32 LLUriParser::normalize() } } - if(mTmpScheme) + if(mTmpScheme && mNormalizedUri.size() > 7) { mNormalizedUri = mNormalizedUri.substr(7); mTmpScheme = false; diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h index 0b43d7ad4b..3aba9dda00 100644 --- a/indra/llcommon/stdtypes.h +++ b/indra/llcommon/stdtypes.h @@ -156,18 +156,15 @@ typedef int intptr_t; * type. */ // narrow_holder is a struct that accepts the passed value as its original -// type and provides templated conversion functions to other types. Once we're -// building with compilers that support Class Template Argument Deduction, we -// can rename this class template 'narrow' and eliminate the narrow() factory -// function below. +// type and provides templated conversion functions to other types. template -class narrow_holder +class narrow { private: FROM mValue; public: - narrow_holder(FROM value): mValue(value) {} + narrow(FROM value): mValue(value) {} /*---------------------- Narrowing unsigned to signed ----------------------*/ template (), which can be -/// implicitly converted to the target type. -template -inline -narrow_holder narrow(FROM value) -{ - return { value }; -} - #endif diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp index c421cc7b1c..8851590189 100644 --- a/indra/llcommon/tests/threadsafeschedule_test.cpp +++ b/indra/llcommon/tests/threadsafeschedule_test.cpp @@ -46,11 +46,12 @@ namespace tut // the real time required for each push() call. Explicitly increment // the timestamp for each one -- but since we're passing explicit // timestamps, make the queue reorder them. - queue.push(Queue::TimeTuple(Queue::Clock::now() + 200ms, "ghi")); + auto now{ Queue::Clock::now() }; + queue.push(Queue::TimeTuple(now + 200ms, "ghi")); // Given the various push() overloads, you have to match the type // exactly: conversions are ambiguous. queue.push("abc"s); - queue.push(Queue::Clock::now() + 100ms, "def"); + queue.push(now + 100ms, "def"); queue.close(); auto entry = queue.pop(); ensure_equals("failed to pop first", std::get<0>(entry), "abc"s); diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index ec5a69a7df..63020a9b6a 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -60,12 +60,15 @@ struct sleepy_robin: public boost::fibers::algo::round_robin /***************************************************************************** * ThreadPoolBase *****************************************************************************/ -LL::ThreadPoolBase::ThreadPoolBase(const std::string& name, size_t threads, - WorkQueueBase* queue): +LL::ThreadPoolBase::ThreadPoolBase(const std::string& name, + size_t threads, + WorkQueueBase* queue, + bool auto_shutdown): super(name), mName("ThreadPool:" + name), mThreadCount(getConfiguredWidth(name, threads)), - mQueue(queue) + mQueue(queue), + mAutomaticShutdown(auto_shutdown) {} void LL::ThreadPoolBase::start() @@ -80,6 +83,14 @@ void LL::ThreadPoolBase::start() run(tname); }); } + + if (!mAutomaticShutdown) + { + // Some threads, like main window's might need to run a bit longer + // to wait for a proper shutdown message + return; + } + // Listen on "LLApp", and when the app is shutting down, close the queue // and join the workers. LLEventPumps::instance().obtain("LLApp").listen( @@ -110,8 +121,11 @@ void LL::ThreadPoolBase::close() mQueue->close(); for (auto& pair: mThreads) { - LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL; - pair.second.join(); + if (pair.second.joinable()) + { + LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL; + pair.second.join(); + } } LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL; } diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h index 61a7bef5be..74056aea17 100644 --- a/indra/llcommon/threadpool.h +++ b/indra/llcommon/threadpool.h @@ -40,7 +40,7 @@ namespace LL * overrides this parameter. */ ThreadPoolBase(const std::string& name, size_t threads, - WorkQueueBase* queue); + WorkQueueBase* queue, bool auto_shutdown = true); virtual ~ThreadPoolBase(); /** @@ -55,10 +55,7 @@ namespace LL * ThreadPool listens for application shutdown messages on the "LLApp" * LLEventPump. Call close() to shut down this ThreadPool early. */ - // [FIRE-32453][BUG-232971] Improve shutdown behaviour. - // void close(); virtual void close(); - // std::string getName() const { return mName; } size_t getWidth() const { return mThreads.size(); } @@ -90,14 +87,14 @@ namespace LL protected: std::unique_ptr mQueue; + std::vector> mThreads; + bool mAutomaticShutdown; private: void run(const std::string& name); - - protected: // [FIRE-32453][BUG-232971] Improve shutdown behaviour. + std::string mName; size_t mThreadCount; - std::vector> mThreads; }; /** @@ -121,8 +118,11 @@ namespace LL * Constraining the queue can cause a submitter to block. Do not * constrain any ThreadPool accepting work from the main thread. */ - ThreadPoolUsing(const std::string& name, size_t threads=1, size_t capacity=1024*1024): - ThreadPoolBase(name, threads, new queue_t(name, capacity)) + ThreadPoolUsing(const std::string& name, + size_t threads=1, + size_t capacity=1024*1024, + bool auto_shutdown = true): + ThreadPoolBase(name, threads, new queue_t(name, capacity), auto_shutdown) {} ~ThreadPoolUsing() override {} diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index 294acd7f63..517076804d 100644 --- a/indra/llcorehttp/_httpservice.cpp +++ b/indra/llcorehttp/_httpservice.cpp @@ -320,6 +320,7 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread) LLMemory::logMemoryInfo(TRUE); //output possible call stacks to log file. + LLError::LLUserWarningMsg::showOutOfMemory(); LLError::LLCallStacks::print(); LL_ERRS() << "Bad memory allocation in HttpService::threadRun()!" << LL_ENDL; diff --git a/indra/llcorehttp/bufferarray.cpp b/indra/llcorehttp/bufferarray.cpp index 8d2e7c6a63..c780c06b4e 100644 --- a/indra/llcorehttp/bufferarray.cpp +++ b/indra/llcorehttp/bufferarray.cpp @@ -288,7 +288,7 @@ int BufferArray::findBlock(size_t pos, size_t * ret_offset) if (pos >= mLen) return -1; // Doesn't exist - const int block_limit(narrow(mBlocks.size())); + const int block_limit(narrow(mBlocks.size())); for (int i(0); i < block_limit; ++i) { if (pos < mBlocks[i]->mUsed) diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp index 763f5a3328..39f9e6be6b 100644 --- a/indra/llimage/llimagebmp.cpp +++ b/indra/llimage/llimagebmp.cpp @@ -321,6 +321,7 @@ bool LLImageBMP::updateData() mColorPalette = new(std::nothrow) U8[color_palette_size]; if (!mColorPalette) { + LLError::LLUserWarningMsg::showOutOfMemory(); LL_WARNS() << "Out of memory in LLImageBMP::updateData(), size: " << color_palette_size << LL_ENDL; return false; } diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp index c8fb9666d9..96e217df0c 100644 --- a/indra/llimage/llimagedimensionsinfo.cpp +++ b/indra/llimage/llimagedimensionsinfo.cpp @@ -50,6 +50,7 @@ bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec) if (file_size == 0) { + mWarning = "texture_load_empty_file"; setLastError("File is empty",src_filename); return false; } @@ -90,6 +91,7 @@ bool LLImageDimensionsInfo::getImageDimensionsBmp() if (signature[0] != 'B' || signature[1] != 'M') { LL_WARNS() << "Not a BMP" << LL_ENDL; + mWarning = "texture_load_format_error"; return false; } @@ -140,6 +142,7 @@ bool LLImageDimensionsInfo::getImageDimensionsPng() if (memcmp(signature, png_magic, PNG_MAGIC_SIZE) != 0) { LL_WARNS() << "Not a PNG" << LL_ENDL; + mWarning = "texture_load_format_error"; return false; } @@ -184,6 +187,7 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg() if (memcmp(signature, jpeg_magic, JPEG_MAGIC_SIZE) != 0) { LL_WARNS() << "Not a JPEG" << LL_ENDL; + mWarning = "texture_load_format_error"; fclose(fp); // Don't leak the file handle return false; } diff --git a/indra/llimage/llimagedimensionsinfo.h b/indra/llimage/llimagedimensionsinfo.h index 8f716c5d02..ade283bb85 100644 --- a/indra/llimage/llimagedimensionsinfo.h +++ b/indra/llimage/llimagedimensionsinfo.h @@ -55,6 +55,12 @@ public: { return mLastError; } + + const std::string& getWarningName() + { + return mWarning; + } + protected: void clean() @@ -129,6 +135,7 @@ protected: std::string mSrcFilename; std::string mLastError; + std::string mWarning; U8* mData; diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 36317a5ba8..ae76c5243f 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -437,6 +437,7 @@ bool LLImageDXT::convertToDXR() U8* newdata = (U8*)ll_aligned_malloc_16(total_bytes); if (!newdata) { + LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Out of memory in LLImageDXT::convertToDXR()" << LL_ENDL; return false; } diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index d43f8dcc3b..ceb02d87c3 100644 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -266,6 +266,7 @@ bool LLImageTGA::updateData() mColorMap = new(std::nothrow) U8[ color_map_bytes ]; if (!mColorMap) { + LLError::LLUserWarningMsg::showOutOfMemory(); LL_WARNS() << "Out of Memory in bool LLImageTGA::updateData(), size: " << color_map_bytes << LL_ENDL; return false; } diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 8bd5bd9584..8d54417e9c 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -35,8 +35,10 @@ class ImageRequest { public: ImageRequest(const LLPointer& image, - S32 discard, BOOL needs_aux, - const LLPointer& responder); + S32 discard, + BOOL needs_aux, + const LLPointer& responder, + U32 request_id); virtual ~ImageRequest(); /*virtual*/ bool processRequest(); @@ -48,6 +50,7 @@ private: // input LLPointer mFormattedImage; S32 mDiscardLevel; + U32 mRequestId; BOOL mNeedsAux; // output LLPointer mDecodedImageRaw; @@ -62,6 +65,7 @@ private: // MAIN THREAD LLImageDecodeThread::LLImageDecodeThread(bool /*threaded*/) + : mDecodeCount(0) { mThreadPool.reset(new LL::ThreadPool("ImageDecode", 8)); mThreadPool->start(); @@ -92,9 +96,10 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage( { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + U32 decode_id = ++mDecodeCount; // Instantiate the ImageRequest right in the lambda, why not? bool posted = mThreadPool->getQueue().post( - [req = ImageRequest(image, discard, needs_aux, responder)] + [req = ImageRequest(image, discard, needs_aux, responder, decode_id)] () mutable { auto done = req.processRequest(); @@ -103,13 +108,10 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage( if (! posted) { LL_DEBUGS() << "Tried to start decoding on shutdown" << LL_ENDL; - // should this return 0? + return 0; } - // It's important to our consumer (LLTextureFetchWorker) that we return a - // nonzero handle. It is NOT important that the nonzero handle be unique: - // nothing is ever done with it except to compare it to zero, or zero it. - return 17; + return decode_id; } void LLImageDecodeThread::shutdown() @@ -123,15 +125,18 @@ LLImageDecodeThread::Responder::~Responder() //---------------------------------------------------------------------------- -ImageRequest::ImageRequest(const LLPointer& image, - S32 discard, BOOL needs_aux, - const LLPointer& responder) +ImageRequest::ImageRequest(const LLPointer& image, + S32 discard, + BOOL needs_aux, + const LLPointer& responder, + U32 request_id) : mFormattedImage(image), mDiscardLevel(discard), mNeedsAux(needs_aux), mDecodedRaw(FALSE), mDecodedAux(FALSE), - mResponder(responder) + mResponder(responder), + mRequestId(request_id) { } @@ -211,7 +216,7 @@ void ImageRequest::finishRequest(bool completed) if (mResponder.notNull()) { bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux); - mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux); + mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux, mRequestId); } // Will automatically be deleted } diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index ca4c0d93d0..b4ab9432e6 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -39,7 +39,7 @@ public: protected: virtual ~Responder(); public: - virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) = 0; + virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32 request_id) = 0; }; public: @@ -53,6 +53,7 @@ public: const LLPointer& responder); size_t getPending(); size_t update(F32 max_time_ms); + S32 getTotalDecodeCount() { return mDecodeCount; } void shutdown(); private: @@ -60,6 +61,7 @@ private: // LLQueuedThread - instead this is the API by which we submit work to the // "ImageDecode" ThreadPool. std::unique_ptr mThreadPool; + LLAtomicU32 mDecodeCount; }; #endif diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index bfeb055599..20ce0a3498 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -5630,9 +5630,9 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) U32 stream_count = data.w.empty() ? 4 : 5; - U32 vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count); + size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count); - if (vert_count < 65535) + if (vert_count < 65535 && vert_count != 0) { std::vector indices; indices.resize(mNumIndices); @@ -5651,6 +5651,13 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) { U32 src_idx = i; U32 dst_idx = remap[i]; + if (dst_idx >= mNumVertices) + { + dst_idx = mNumVertices - 1; + // Shouldn't happen, figure out what gets returned in remap and why. + llassert(false); + LL_DEBUGS_ONCE("LLVOLUME") << "Invalid destination index, substituting" << LL_ENDL; + } mIndices[i] = dst_idx; mPositions[dst_idx].load3(data.p[src_idx].mV); @@ -5684,6 +5691,10 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) } else { + if (vert_count == 0) + { + LL_WARNS_ONCE("LLVOLUME") << "meshopt_generateVertexRemapMulti failed to process a model or model was invalid" << LL_ENDL; + } // blew past the max vertex size limit, use legacy tangent generation which never adds verts createTangents(); } diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index 93d5cfc131..212d0619d1 100644 --- a/indra/llmessage/llxfer.cpp +++ b/indra/llmessage/llxfer.cpp @@ -386,12 +386,3 @@ std::ostream& operator<< (std::ostream& os, LLXfer &hh) os << hh.getFileName() ; return os; } - - - - - - - - - diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index c6777e9133..eae19a8f62 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -1056,7 +1056,12 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) weight_map::iterator iterPos = mSkinWeights.begin(); weight_map::iterator iterEnd = mSkinWeights.end(); - llassert(!mSkinWeights.empty()); + if (mSkinWeights.empty()) + { + // function calls iter->second on all return paths + // everything that calls this function should precheck that there is data. + LL_ERRS() << "called getJointInfluences with empty weights list" << LL_ENDL; + } for ( ; iterPos!=iterEnd; ++iterPos ) { @@ -1083,11 +1088,16 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) const F32 epsilon = 1e-5f; weight_map::iterator iter_up = mSkinWeights.lower_bound(pos); weight_map::iterator iter_down = iter_up; - if (iter_up != mSkinWeights.end()) - { - iter_down = ++iter_up; - } - weight_map::iterator best = iter_up; + weight_map::iterator best = iter_up; + if (iter_up != mSkinWeights.end()) + { + iter_down = ++iter_up; + } + else + { + // Assumes that there is at least one element + --best; + } // FIRE-9251; There is no way iter can be valid here, otherwise we had hit the if branch and not the else branch. // F32 min_dist = (iter->first - pos).magVec(); diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 113d12a65a..b2ca583611 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -101,6 +101,17 @@ void APIENTRY gl_debug_callback(GLenum source, return; }*/ + if (gGLManager.mIsDisabled && + severity == GL_DEBUG_SEVERITY_HIGH_ARB && + source == GL_DEBUG_SOURCE_API_ARB && + type == GL_DEBUG_TYPE_ERROR_ARB && + id == GL_INVALID_VALUE) + { + // Suppress messages about deleting already deleted objects called from LLViewerWindow::stopGL() + // "GL_INVALID_VALUE error generated. Handle does not refer to an object generated by OpenGL." + return; + } + // list of messages to suppress const char* suppress[] = { @@ -155,8 +166,9 @@ void APIENTRY gl_debug_callback(GLenum source, glGetBufferParameteriv(GL_UNIFORM_BUFFER, GL_BUFFER_SIZE, &ubo_size); glGetBufferParameteriv(GL_UNIFORM_BUFFER, GL_BUFFER_IMMUTABLE_STORAGE, &ubo_immutable); } - - if (severity == GL_DEBUG_SEVERITY_HIGH) + + // No needs to halt when is called from LLViewerWindow::stopGL() + if (severity == GL_DEBUG_SEVERITY_HIGH && !gGLManager.mIsDisabled) { LL_ERRS() << "Halting on GL Error" << LL_ENDL; } diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 9e3ef13bba..e0a7c2c958 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1353,6 +1353,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt scratch = new(std::nothrow) U32[width * height]; if (!scratch) { + LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) << " bytes for a manual image W" << width << " H" << height << LL_ENDL; } @@ -1378,6 +1379,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt scratch = new(std::nothrow) U32[width * height]; if (!scratch) { + LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) << " bytes for a manual image W" << width << " H" << height << LL_ENDL; } @@ -1406,6 +1408,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt scratch = new(std::nothrow) U32[width * height]; if (!scratch) { + LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) << " bytes for a manual image W" << width << " H" << height << LL_ENDL; } diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 24b0653d26..92432b4f38 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -862,7 +862,7 @@ LLRender::~LLRender() shutdown(); } -void LLRender::init(bool needs_vertex_buffer) +bool LLRender::init(bool needs_vertex_buffer) { #if LL_WINDOWS if (gGLManager.mHasDebugOutput && gDebugGL) @@ -884,6 +884,13 @@ void LLRender::init(bool needs_vertex_buffer) // necessary for reflection maps glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); +#if LL_WINDOWS + if (glGenVertexArrays == nullptr) + { + return false; + } +#endif + { //bind a dummy vertex array object so we're core profile compliant U32 ret; glGenVertexArrays(1, &ret); @@ -904,6 +911,8 @@ void LLRender::init(bool needs_vertex_buffer) stop_glerror(); mMaxLineWidthSmooth = range[1]; // + + return true; } void LLRender::initVertexBuffer() diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 6cc570543b..1956715e5b 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -386,7 +386,7 @@ public: LLRender(); ~LLRender(); - void init(bool needs_vertex_buffer); + bool init(bool needs_vertex_buffer); void initVertexBuffer(); void resetVertexBuffer(); void shutdown(); diff --git a/indra/llrender/llrendernavprim.cpp b/indra/llrender/llrendernavprim.cpp index d610a44bc6..eea3077632 100644 --- a/indra/llrender/llrendernavprim.cpp +++ b/indra/llrender/llrendernavprim.cpp @@ -40,20 +40,20 @@ LLRenderNavPrim gRenderNav; //============================================================================= void LLRenderNavPrim::renderLLTri( const LLVector3& a, const LLVector3& b, const LLVector3& c, const LLColor4U& color ) const { - LLColor4 cV(color); - gGL.color4fv( cV.mV ); - gGL.begin(LLRender::TRIANGLES); + gGL.color4ubv(color.mV); + + gGL.begin(LLRender::TRIANGLES); { gGL.vertex3fv( a.mV ); gGL.vertex3fv( b.mV ); gGL.vertex3fv( c.mV ); } - gGL.end(); + gGL.end(); } //============================================================================= void LLRenderNavPrim::renderNavMeshVB( U32 mode, LLVertexBuffer* pVBO, int vertCnt ) { pVBO->setBuffer(); - pVBO->drawArrays( mode, 0, vertCnt ); + pVBO->drawArrays( mode, 0, vertCnt ); } //============================================================================= diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index 896a34cac4..496c34c38b 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -126,12 +126,12 @@ public: void setSelected(bool is_selected); - bool getCollapsible() {return mCollapsible;}; + bool getCollapsible() { return mCollapsible; }; - void setCollapsible(bool collapsible) {mCollapsible = collapsible;}; + void setCollapsible(bool collapsible) { mCollapsible = collapsible; }; void changeOpenClose(bool is_open); - void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close;}; + void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close; }; bool canOpenClose() const { return mCanOpenClose; }; virtual BOOL postBuild(); @@ -142,8 +142,8 @@ public: void draw(); - void storeOpenCloseState (); - void restoreOpenCloseState (); + void storeOpenCloseState(); + void restoreOpenCloseState(); protected: LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&); diff --git a/indra/llui/llcontainerview.cpp b/indra/llui/llcontainerview.cpp index 4b057fa62c..b34496c1d3 100644 --- a/indra/llui/llcontainerview.cpp +++ b/indra/llui/llcontainerview.cpp @@ -296,7 +296,7 @@ void LLContainerView::setLabel(const std::string& label) mLabel = label; } -void LLContainerView::setDisplayChildren(const BOOL displayChildren) +void LLContainerView::setDisplayChildren(BOOL displayChildren) { mDisplayChildren = displayChildren; for (child_list_const_iter_t child_iter = getChildList()->begin(); diff --git a/indra/llui/llcontainerview.h b/indra/llui/llcontainerview.h index 48ec36a861..7f69670230 100644 --- a/indra/llui/llcontainerview.h +++ b/indra/llui/llcontainerview.h @@ -86,7 +86,7 @@ public: void setLabel(const std::string& label); void showLabel(BOOL show) { mShowLabel = show; } - void setDisplayChildren(const BOOL displayChildren); + void setDisplayChildren(BOOL displayChildren); BOOL getDisplayChildren() { return mDisplayChildren; } void setScrollContainer(LLScrollContainer* scroll) {mScrollContainer = scroll;} diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 4363d2c475..c5fb9bb459 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -1373,26 +1373,28 @@ void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show) mForceShowingUnmatchedItems = show; } -void LLFlatListViewEx::setFilterSubString(const std::string& filter_str) +void LLFlatListViewEx::setFilterSubString(const std::string& filter_str, bool notify_parent) { if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString)) { mFilterSubString = filter_str; updateNoItemsMessage(mFilterSubString); - filterItems(); + filterItems(false, notify_parent); } } -void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action) +bool LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action) { - if (!item) return; + if (!item) + return false; + + BOOL visible = TRUE; // 0 signifies that filter is matched, // i.e. we don't hide items that don't support 'match_filter' action, separators etc. if (0 == item->notify(action)) { mHasMatchedItems = true; - item->setVisible(true); } else { @@ -1400,34 +1402,45 @@ void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action) if (!mForceShowingUnmatchedItems) { selectItem(item, false); + visible = FALSE; } - item->setVisible(mForceShowingUnmatchedItems); } + + if (item->getVisible() != visible) + { + item->setVisible(visible); + return true; + } + + return false; } -void LLFlatListViewEx::filterItems() +void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent) { - typedef std::vector item_panel_list_t; - std::string cur_filter = mFilterSubString; LLStringUtil::toUpper(cur_filter); LLSD action; action.with("match_filter", cur_filter); - item_panel_list_t items; - getItems(items); - mHasMatchedItems = false; - item_panel_list_t::iterator iter = items.begin(), iter_end = items.end(); - while (iter < iter_end) + bool visibility_changed = false; + pairs_const_iterator_t iter = getItemPairs().begin(), iter_end = getItemPairs().end(); + while (iter != iter_end) { - LLPanel* pItem = *(iter++); - updateItemVisibility(pItem, action); + LLPanel* pItem = (*(iter++))->first; + visibility_changed |= updateItemVisibility(pItem, action); } - sort(); - notifyParentItemsRectChanged(); + if (re_sort) + { + sort(); + } + + if (visibility_changed && notify_parent) + { + notifyParentItemsRectChanged(); + } } bool LLFlatListViewEx::hasMatchedItems() diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 7fe5d90876..054dab44d5 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -308,6 +308,7 @@ public: virtual S32 notify(const LLSD& info) ; virtual ~LLFlatListView(); + protected: /** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */ @@ -383,7 +384,9 @@ protected: LLRect getLastSelectedItemRect(); - void ensureSelectedVisible(); + void ensureSelectedVisible(); + + const pairs_list_t& getItemPairs() { return mItemPairs; } private: @@ -496,14 +499,14 @@ public: /** * Sets up new filter string and filters the list. */ - void setFilterSubString(const std::string& filter_str); + void setFilterSubString(const std::string& filter_str, bool notify_parent); std::string getFilterSubString() { return mFilterSubString; } /** * Filters the list, rearranges and notifies parent about shape changes. * Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration. */ - void filterItems(); + void filterItems(bool re_sort, bool notify_parent); /** * Returns true if last call of filterItems() found at least one matching item @@ -527,7 +530,7 @@ protected: * @param item - item we are changing * @param item - action - parameters to determin visibility from */ - void updateItemVisibility(LLPanel* item, const LLSD &action); + bool updateItemVisibility(LLPanel* item, const LLSD &action); private: std::string mNoFilteredItemsMsg; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index dbd59e3393..ed5a256764 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -541,7 +541,6 @@ void LLFloater::enableResizeCtrls(bool enable, bool width, bool height) void LLFloater::destroy() { - gFloaterView->onDestroyFloater(this); // LLFloaterReg should be synchronized with "dead" floater to avoid returning dead instance before // it was deleted via LLMortician::updateClass(). See EXT-8458. LLFloaterReg::removeInstance(mInstanceName, mKey); @@ -2631,8 +2630,7 @@ LLFloaterView::LLFloaterView (const Params& p) mSnapOffsetBottom(0), mSnapOffsetChatBar(0), mSnapOffsetLeft(0), - mSnapOffsetRight(0), - mFrontChild(NULL) + mSnapOffsetRight(0) { mSnapView = getHandle(); } @@ -2788,7 +2786,8 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore if (!child) return; - if (mFrontChild == child) + LLFloater* front_child = mFrontChildHandle.get(); + if (front_child == child) { if (give_focus && child->canFocusStealFrontmost() && !gFocusMgr.childHasKeyboardFocus(child)) { @@ -2797,12 +2796,12 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore return; } - if (mFrontChild && !mFrontChild->isDead()) + if (front_child && !front_child->isDead() && front_child->getVisible()) { - mFrontChild->goneFromFront(); + front_child->goneFromFront(); } - mFrontChild = child; + mFrontChildHandle = child->getHandle(); // *TODO: make this respect floater's mAutoFocus value, instead of // using parameter @@ -3389,7 +3388,8 @@ LLFloater *LLFloaterView::getBackmost() const void LLFloaterView::syncFloaterTabOrder() { - if (mFrontChild && !mFrontChild->isDead() && mFrontChild->getIsChrome()) + LLFloater* front_child = mFrontChildHandle.get(); + if (front_child && front_child->getIsChrome()) return; // look for a visible modal dialog, starting from first @@ -3427,11 +3427,12 @@ void LLFloaterView::syncFloaterTabOrder() LLFloater* floaterp = dynamic_cast(*child_it); if (gFocusMgr.childHasKeyboardFocus(floaterp)) { - if (mFrontChild != floaterp) + LLFloater* front_child = mFrontChildHandle.get(); + if (front_child != floaterp) { // Grab a list of the top floaters that want to stay on top of the focused floater std::list listTop; - if (mFrontChild && !mFrontChild->canFocusStealFrontmost()) + if (front_child && !front_child->canFocusStealFrontmost()) { for (LLView* childp : *getChildList()) { @@ -3451,7 +3452,7 @@ void LLFloaterView::syncFloaterTabOrder() { sendChildToFront(childp); } - mFrontChild = listTop.back(); + mFrontChildHandle = listTop.back()->getHandle(); } } @@ -3547,14 +3548,6 @@ void LLFloaterView::setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LL } } -void LLFloaterView::onDestroyFloater(LLFloater* floater) -{ - if (mFrontChild == floater) - { - mFrontChild = nullptr; - } -} - // Prevent floaters being dragged under main chat bar void LLFloaterView::setMainChatbarRect(LLLayoutPanel* panel, const LLRect& chatbar_rect) { diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 21b132f239..71c46b1300 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -645,7 +645,6 @@ public: // Fix for bad edge snapping void setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect); - void onDestroyFloater(LLFloater* floater); // Prevent floaters being dragged under main chat bar void setMainChatbarRect(LLLayoutPanel* panel, const LLRect& chatbar_rect); @@ -670,7 +669,7 @@ private: S32 mMinimizePositionVOffset; typedef std::vector, boost::signals2::connection> > hidden_floaters_t; hidden_floaters_t mHiddenFloaters; - LLFloater * mFrontChild; + LLHandle mFrontChildHandle; // Prevent floaters being dragged under main chat bar LLRect mMainChatbarRect; diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 9606d6e7ca..b31c4e8c1c 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -206,14 +206,18 @@ LLFolderViewItem::~LLFolderViewItem() BOOL LLFolderViewItem::postBuild() { - LLFolderViewModelItem& vmi = *getViewModelItem(); - // getDisplayName() is expensive (due to internal getLabelSuffix() and name building) - // it also sets search strings so it requires a filter reset - mLabel = vmi.getDisplayName(); - setToolTip(vmi.getName()); + LLFolderViewModelItem* vmi = getViewModelItem(); + llassert(vmi); // not supposed to happen, if happens, find out why and fix + if (vmi) + { + // getDisplayName() is expensive (due to internal getLabelSuffix() and name building) + // it also sets search strings so it requires a filter reset + mLabel = vmi->getDisplayName(); + setToolTip(vmi->getName()); - // Dirty the filter flag of the model from the view (CHUI-849) - vmi.dirtyFilter(); + // Dirty the filter flag of the model from the view (CHUI-849) + vmi->dirtyFilter(); + } // Don't do full refresh on constructor if it is possible to avoid // it significantly slows down bulk view creation. diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index 4cf7bc4256..46166ca3f7 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -502,7 +502,7 @@ LLTrace::BlockTimerStatHandle FTM_SYNTAX_COLORING("Syntax Coloring"); // Walk through a string, applying the rules specified by the keyword token list and // create a list of color segments. -void LLKeywords::findSegments(std::vector* seg_list, const LLWString& wtext, const LLColor4 &defaultColor, LLTextEditor& editor) +void LLKeywords::findSegments(std::vector* seg_list, const LLWString& wtext, LLTextEditor& editor, LLStyleConstSP style) { LL_RECORD_BLOCK_TIME(FTM_SYNTAX_COLORING); seg_list->clear(); @@ -515,10 +515,10 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLW S32 text_len = wtext.size() + 1; // Script editor ignoring font selection - //seg_list->push_back( new LLNormalTextSegment( defaultColor, 0, text_len, editor ) ); - LLStyleSP style = getDefaultStyle(editor); - style->setColor(defaultColor); - seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) ); + //seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) ); + LLStyleSP actual_style = getDefaultStyle(editor); + actual_style->setColor(style->getColor()); + seg_list->push_back( new LLNormalTextSegment( actual_style, 0, text_len, editor ) ); // const llwchar* base = wtext.c_str(); @@ -530,11 +530,11 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLW if( *cur == '\n' ) { // Script editor ignoring font selection - //LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(cur-base); + //LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, cur-base); LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(getDefaultStyle(editor), cur-base); // text_segment->setToken( 0 ); - insertSegment( *seg_list, text_segment, text_len, defaultColor, editor); + insertSegment( *seg_list, text_segment, text_len, style, editor); cur++; if( !*cur || *cur == '\n' ) { @@ -572,7 +572,7 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLW S32 seg_end = cur - base; //create segments from seg_start to seg_end - insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, defaultColor, editor); + insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, style, editor); line_done = TRUE; // to break out of second loop. break; } @@ -679,7 +679,7 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLW seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead(); } - insertSegments(wtext, *seg_list,cur_delimiter, text_len, seg_start, seg_end, defaultColor, editor); + insertSegments(wtext, *seg_list,cur_delimiter, text_len, seg_start, seg_end, style, editor); /* // Script editor ignoring font selection //LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_delimiter->getColor(), seg_start, seg_end, editor ); @@ -723,7 +723,7 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLW // LL_INFOS("SyntaxLSL") << "Seg: [" << word.c_str() << "]" << LL_ENDL; - insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, defaultColor, editor); + insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, style, editor); } cur += seg_len; continue; @@ -738,9 +738,12 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLW } } -void LLKeywords::insertSegments(const LLWString& wtext, std::vector& seg_list, LLKeywordToken* cur_token, S32 text_len, S32 seg_start, S32 seg_end, const LLColor4 &defaultColor, LLTextEditor& editor ) +void LLKeywords::insertSegments(const LLWString& wtext, std::vector& seg_list, LLKeywordToken* cur_token, S32 text_len, S32 seg_start, S32 seg_end, LLStyleConstSP style, LLTextEditor& editor ) { std::string::size_type pos = wtext.find('\n',seg_start); + + // Script editor ignoring font selection + //LLStyleConstSP cur_token_style = new LLStyle(LLStyle::Params().font(style->getFont()).color(cur_token->getColor())); while (pos!=-1 && pos < (std::string::size_type)seg_end) { @@ -753,28 +756,28 @@ void LLKeywords::insertSegments(const LLWString& wtext, std::vector text_segment->setToken( cur_token ); - insertSegment( seg_list, text_segment, text_len, defaultColor, editor); + insertSegment( seg_list, text_segment, text_len, style, editor); } // Script editor ignoring font selection - //LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(pos); + //LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, pos); LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(getDefaultStyle(editor), pos); // text_segment->setToken( cur_token ); - insertSegment( seg_list, text_segment, text_len, defaultColor, editor); + insertSegment( seg_list, text_segment, text_len, style, editor); seg_start = pos+1; pos = wtext.find('\n',seg_start); } // Script editor ignoring font selection - //LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_token->getColor(), seg_start, seg_end, editor ); - LLStyleSP style = getDefaultStyle(editor); - style->setColor(cur_token->getColor()); - LLTextSegmentPtr text_segment = new LLNormalTextSegment( style, seg_start, seg_end, editor ); + //LLTextSegmentPtr text_segment = new LLNormalTextSegment(cur_token_style, seg_start, seg_end, editor); + LLStyleSP actual_style = getDefaultStyle(editor); + actual_style->setColor(cur_token->getColor()); + LLTextSegmentPtr text_segment = new LLNormalTextSegment(actual_style, seg_start, seg_end, editor); // text_segment->setToken( cur_token ); - insertSegment( seg_list, text_segment, text_len, defaultColor, editor); + insertSegment( seg_list, text_segment, text_len, style, editor); } void LLKeywords::insertSegment(std::vector& seg_list, LLTextSegmentPtr new_segment, S32 text_len, const LLColor4 &defaultColor, LLTextEditor& editor ) @@ -803,6 +806,32 @@ void LLKeywords::insertSegment(std::vector& seg_list, LLTextSe } } +void LLKeywords::insertSegment(std::vector& seg_list, LLTextSegmentPtr new_segment, S32 text_len, LLStyleConstSP style, LLTextEditor& editor ) +{ + LLTextSegmentPtr last = seg_list.back(); + S32 new_seg_end = new_segment->getEnd(); + + if( new_segment->getStart() == last->getStart() ) + { + seg_list.pop_back(); + } + else + { + last->setEnd( new_segment->getStart() ); + } + seg_list.push_back( new_segment ); + + if( new_seg_end < text_len ) + { + // Script editor ignoring font selection + //seg_list.push_back( new LLNormalTextSegment( style, new_seg_end, text_len, editor ) ); + LLStyleSP actual_style = getDefaultStyle(editor); + actual_style->setColor(style->getColor()); + seg_list.push_back(new LLNormalTextSegment(actual_style, new_seg_end, text_len, editor)); + // + } +} + // Re-add support for Cinder's legacy file format bool LLKeywords::loadFromLegacyFile(const std::string& filename) { diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h index 0ee4f70692..9314d08c82 100644 --- a/indra/llui/llkeywords.h +++ b/indra/llui/llkeywords.h @@ -29,6 +29,7 @@ #include "lldir.h" +#include "llstyle.h" #include "llstring.h" #include "v3color.h" #include "v4color.h" @@ -121,8 +122,8 @@ public: void findSegments(std::vector *seg_list, const LLWString& text, - const LLColor4 &defaultColor, - class LLTextEditor& editor); + class LLTextEditor& editor, + LLStyleConstSP style); void initialize(LLSD SyntaxXML); void processTokens(); @@ -187,9 +188,11 @@ protected: S32 text_len, S32 seg_start, S32 seg_end, - const LLColor4 &defaultColor, + LLStyleConstSP style, LLTextEditor& editor); + void insertSegment(std::vector& seg_list, LLTextSegmentPtr new_segment, S32 text_len, LLStyleConstSP style, LLTextEditor& editor ); + bool mLoaded; LLSD mSyntax; word_token_map_t mWordTokenMap; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 286d4602c4..7aa9c11be4 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -1811,7 +1811,8 @@ LLMenuGL::LLMenuGL(const LLMenuGL::Params& p) mNeedsArrange(FALSE), mAlwaysShowMenu(FALSE), mResetScrollPositionOnShow(true), - mShortcutPad(p.shortcut_pad) + mShortcutPad(p.shortcut_pad), + mFont(p.font) { typedef boost::tokenizer > tokenizer; boost::char_separator sep("_"); @@ -3682,6 +3683,7 @@ BOOL LLMenuBarGL::appendMenu( LLMenuGL* menu ) p.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor"); p.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); p.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); + p.font = menu->getFont(); LLMenuItemBranchDownGL* branch = LLUICtrlFactory::create(p); success &= branch->addToAcceleratorList(&mAccelerators); diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index f3bc724644..a35c0fcf7d 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -563,6 +563,8 @@ public: // add a context menu branch BOOL appendContextSubMenu(LLMenuGL *menu); + const LLFontGL *getFont() const { return mFont; } + // Items-accessor typedef std::list< LLMenuItemGL* > item_list_t; item_list_t* getItems() { return &mItems; } @@ -599,6 +601,9 @@ protected: BOOL mKeepFixedSize; BOOL mNeedsArrange; + // Font for top menu items only + const LLFontGL* mFont; + private: diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 18101d7b82..9572971fc7 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -1562,6 +1562,7 @@ bool LLNotifications::loadTemplates() if (!success || root.isNull() || !root->hasName( "notifications" )) { + LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL; return false; } @@ -1572,6 +1573,7 @@ bool LLNotifications::loadTemplates() if(!params.validateBlock()) { + LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); LL_ERRS() << "Problem reading XUI from UI Notifications file: " << base_filename << LL_ENDL; return false; } @@ -1638,6 +1640,7 @@ bool LLNotifications::loadVisibilityRules() if(!params.validateBlock()) { + LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); LL_ERRS() << "Problem reading UI Notification Visibility Rules file: " << full_filename << LL_ENDL; return false; } diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp index d8f0bda543..fb82f594aa 100644 --- a/indra/llui/llstatbar.cpp +++ b/indra/llui/llstatbar.cpp @@ -184,7 +184,7 @@ LLStatBar::LLStatBar(const Params& p) mTargetMinBar(llmin(p.bar_min, p.bar_max)), mTargetMaxBar(llmax(p.bar_max, p.bar_min)), mCurMaxBar(p.bar_max), - mCurMinBar(0), + mCurMinBar(0), mDecimalDigits(p.decimal_digits), mNumHistoryFrames(p.num_frames), mNumShortHistoryFrames(p.num_frames_short), @@ -279,9 +279,6 @@ BOOL LLStatBar::handleHover(S32 x, S32 y, MASK mask) case STAT_SAMPLE: LLToolTipMgr::instance().show(LLToolTip::Params().message(mStat.sampleStatp->getDescription()).sticky_rect(calcScreenRect())); break; - case STAT_MEM: - LLToolTipMgr::instance().show(LLToolTip::Params().message(mStat.memStatp->getDescription()).sticky_rect(calcScreenRect())); - break; default: break; } @@ -430,18 +427,6 @@ void LLStatBar::draw() } } break; - case STAT_MEM: - { - const LLTrace::StatType& mem_stat = *mStat.memStatp; - - unit_label = mUnitLabel.empty() ? mem_stat.getUnitLabel() : mUnitLabel; - current = last_frame_recording.getLastValue(mem_stat).value(); - min = frame_recording.getPeriodMin(mem_stat, num_frames).value(); - max = frame_recording.getPeriodMax(mem_stat, num_frames).value(); - mean = frame_recording.getPeriodMean(mem_stat, num_frames).value(); - display_value = current; - } - break; default: break; } @@ -560,11 +545,6 @@ void LLStatBar::draw() max_value = recording.getMax(*mStat.sampleStatp); num_samples = recording.getSampleCount(*mStat.sampleStatp); break; - case STAT_MEM: - min_value = recording.getMin(*mStat.memStatp).value(); - max_value = recording.getMax(*mStat.memStatp).value(); - num_samples = 1; - break; default: break; } @@ -661,14 +641,8 @@ void LLStatBar::setStat(const std::string& stat_name) mStat.sampleStatp = sample_stat.get(); mStatType = STAT_SAMPLE; } - else if (auto mem_stat = StatType::getInstance(stat_name)) - { - mStat.memStatp = mem_stat.get(); - mStatType = STAT_MEM; - } } - void LLStatBar::setRange(F32 bar_min, F32 bar_max) { mTargetMinBar = llmin(bar_min, bar_max); diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h index 6c84fb8e38..49622485be 100644 --- a/indra/llui/llstatbar.h +++ b/indra/llui/llstatbar.h @@ -100,17 +100,15 @@ private: STAT_NONE, STAT_COUNT, STAT_EVENT, - STAT_SAMPLE, - STAT_MEM + STAT_SAMPLE } mStatType; union { - void* valid; + void* valid; const LLTrace::StatType* countStatp; const LLTrace::StatType* eventStatp; - const LLTrace::StatType* sampleStatp; - const LLTrace::StatType* memStatp; + const LLTrace::StatType* sampleStatp; } mStat; LLUIString mLabel; diff --git a/indra/llui/llstatview.cpp b/indra/llui/llstatview.cpp index bb4969c81f..03f2fb7cc0 100644 --- a/indra/llui/llstatview.cpp +++ b/indra/llui/llstatview.cpp @@ -58,10 +58,7 @@ LLStatView::~LLStatView() } } - static StatViewRegistry::Register r1("stat_bar"); static StatViewRegistry::Register r2("stat_view"); // stat_view can be a child of panels/etc. static LLDefaultChildRegistry::Register r3("stat_view"); - - diff --git a/indra/llui/llstatview.h b/indra/llui/llstatview.h index af4db7d7ea..044f0a8679 100644 --- a/indra/llui/llstatview.h +++ b/indra/llui/llstatview.h @@ -63,7 +63,7 @@ protected: friend class LLUICtrlFactory; protected: - std::string mSetting; - + const std::string mSetting; }; + #endif // LL_STATVIEW_ diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 124b0d073b..3928cb5655 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -1657,25 +1657,23 @@ BOOL LLTabContainer::selectTab(S32 which) LLTabTuple* selected_tuple = getTab(which); if (!selected_tuple) - { return FALSE; - } - + LLSD cbdata; if (selected_tuple->mTabPanel) cbdata = selected_tuple->mTabPanel->getName(); - BOOL res = FALSE; - if( !mValidateSignal || (*mValidateSignal)( this, cbdata ) ) + BOOL result = FALSE; + if (!mValidateSignal || (*mValidateSignal)(this, cbdata)) { - res = setTab(which); - if (res && mCommitSignal) + result = setTab(which); + if (result && mCommitSignal) { (*mCommitSignal)(this, cbdata); } } - - return res; + + return result; } // private diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 978e7cf25e..69aedb647b 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -3829,7 +3829,7 @@ BOOL LLNormalTextSegment::handleToolTip(S32 x, S32 y, MASK mask) if (mToken && !mToken->getToolTip().empty()) { const LLWString& wmsg = mToken->getToolTip(); - LLToolTipMgr::instance().show(wstring_to_utf8str(wmsg)); + LLToolTipMgr::instance().show(wstring_to_utf8str(wmsg), (mToken->getType() == LLKeywordToken::TT_FUNCTION)); return TRUE; } // or do we have an explicitly set tooltip (e.g., for Urls) diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 9b98c60c63..e938fa3c8f 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2048,7 +2048,8 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) } if (mEnableTooltipPaste && - LLToolTipMgr::instance().toolTipVisible() && + LLToolTipMgr::instance().toolTipVisible() && + LLToolTipMgr::instance().isTooltipPastable() && KEY_TAB == key) { // Paste the first line of a tooltip into the editor std::string message; @@ -2901,6 +2902,7 @@ BOOL LLTextEditor::importBuffer(const char* buffer, S32 length ) char* text = new char[ text_len + 1]; if (text == NULL) { + LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Memory allocation failure." << LL_ENDL; return FALSE; } diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index b286912f17..62371a9208 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -154,7 +154,8 @@ LLToolTip::Params::Params() text_color("text_color"), time_based_media("time_based_media", false), web_based_media("web_based_media", false), - media_playing("media_playing", false) + media_playing("media_playing", false), + allow_paste_tooltip("allow_paste_tooltip", false) { changeDefault(chrome, true); } @@ -167,7 +168,8 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p) mTextBox(NULL), mInfoButton(NULL), mPlayMediaButton(NULL), - mHomePageButton(NULL) + mHomePageButton(NULL), + mIsTooltipPastable(p.allow_paste_tooltip) { LLTextBox::Params params; params.name = params.initial_value().asString(); @@ -289,6 +291,8 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p) mTextBox->setText(p.message()); } + mIsTooltipPastable = p.allow_paste_tooltip; + updateTextBox(); snapToChildren(); } @@ -483,9 +487,9 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params) } -void LLToolTipMgr::show(const std::string& msg) +void LLToolTipMgr::show(const std::string& msg, bool allow_paste_tooltip) { - show(LLToolTip::Params().message(msg)); + show(LLToolTip::Params().message(msg).allow_paste_tooltip(allow_paste_tooltip)); } void LLToolTipMgr::show(const LLToolTip::Params& params) @@ -625,5 +629,13 @@ void LLToolTipMgr::getToolTipMessage(std::string & message) } } +bool LLToolTipMgr::isTooltipPastable() +{ + if (toolTipVisible()) + { + return mToolTip->isTooltipPastable(); + } + return false; + } // EOF diff --git a/indra/llui/lltooltip.h b/indra/llui/lltooltip.h index 86943625ff..fef5e7c75f 100644 --- a/indra/llui/lltooltip.h +++ b/indra/llui/lltooltip.h @@ -94,6 +94,8 @@ public: padding; Optional wrap; + Optional allow_paste_tooltip; + Params(); }; /*virtual*/ void draw(); @@ -109,6 +111,7 @@ public: virtual void initFromParams(const LLToolTip::Params& params); void getToolTipMessage(std::string & message); + bool isTooltipPastable() { return mIsTooltipPastable; } protected: void updateTextBox(); @@ -125,6 +128,8 @@ protected: bool mHasClickCallback; S32 mPadding; // pixels S32 mMaxWidth; + + bool mIsTooltipPastable; }; // used for the inspector tooltips which need different background images etc. @@ -142,7 +147,7 @@ class LLToolTipMgr : public LLSingleton public: void show(const LLToolTip::Params& params); - void show(const std::string& message); + void show(const std::string& message, bool allow_paste_tooltip = false); void unblockToolTips(); void blockToolTips(); @@ -154,6 +159,7 @@ public: void updateToolTipVisibility(); void getToolTipMessage(std::string & message); + bool isTooltipPastable(); private: void createToolTip(const LLToolTip::Params& params); diff --git a/indra/llui/lltransutil.cpp b/indra/llui/lltransutil.cpp index ebbdae2e9a..dbf50f818c 100644 --- a/indra/llui/lltransutil.cpp +++ b/indra/llui/lltransutil.cpp @@ -44,8 +44,13 @@ bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::setdumpCurrentDirectories(LLError::LEVEL_WARN); - LL_ERRS() << "Couldn't load string table " << xml_filename << ". Please reinstall viewer from https://www.firestormviewer.org/choose-your-platform/ and contact https://www.firestormviewer.org/support if issue persists after reinstall." << LL_ENDL; + LL_ERRS() << "Couldn't load string table " << xml_filename << " " << errno << LL_ENDL; return false; } @@ -60,6 +65,7 @@ bool LLTransUtil::parseLanguageStrings(const std::string& xml_filename) if (!success) { + LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS() << "Couldn't load localization table " << xml_filename << LL_ENDL; return false; } diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index c1d6696b69..3c94858c0b 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -237,14 +237,20 @@ bool LLUrlEntryBase::isWikiLinkCorrect(const std::string &labeled_url) const std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) const { + if (url.empty()) + { + return url; + } LLUriParser up(escapeUrl(url)); - up.normalize(); + if (up.normalize() == 0) + { + std::string label; + up.extractParts(); + up.glueFirst(label); - std::string label; - up.extractParts(); - up.glueFirst(label); - - return unescapeUrl(label); + return unescapeUrl(label); + } + return std::string(); } std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index dcc2197982..b949320b27 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -293,16 +293,18 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL //if (match_entry == mUrlEntryTrusted) //{ // LLUriParser up(url); - // up.normalize(); - // url = up.normalizedUri(); + // if (up.normalize() == 0) + // { + // url = up.normalizedUri(); + // } //} if (match_entry != mUrlEntryNoLink && match_entry == mUrlEntryTrustedUrl) { LLUriParser up(url); - if (!up.normalize()) - { - url = up.normalizedUri(); - } + if (up.normalize() == 0) + { + url = up.normalizedUri(); + } } // diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 16e3c99608..a9be33bfe9 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -37,7 +37,6 @@ #include "llwindowcallbacks.h" // Linden library includes -#include "llapp.h" // [FIRE-32453][BUG-232971] Improve shutdown behaviour. #include "llerror.h" #include "llexception.h" #include "llfasttimer.h" @@ -94,7 +93,6 @@ const UINT WM_DUMMY_(WM_USER + 0x0017); const UINT WM_POST_FUNCTION_(WM_USER + 0x0018); extern BOOL gDebugWindowProc; -extern BOOL gDisconnected; // [FIRE-32453][BUG-232971] Improve shutdown behaviour. static std::thread::id sWindowThreadId; static std::thread::id sMainThreadId; @@ -353,7 +351,10 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool LLWindowWin32Thread(); void run() override; - void close() override; // [FIRE-32453][BUG-232971] Improve shutdown behaviour. + void close() override; + + // closes queue, wakes thread, waits until thread closes + void wakeAndDestroy(); void glReady() { @@ -366,6 +367,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // initialize D3D (if DXGI cannot be used) void initD3D(); + //clean up DXGI/D3D resources + void cleanupDX(); + // call periodically to update available VRAM void updateVRAMUsage(); @@ -415,8 +419,8 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool using FuncType = std::function; // call GetMessage() and pull enqueue messages for later processing void gatherInput(); - HWND mWindowHandle = NULL; - HDC mhDC = 0; + HWND mWindowHandleThrd = NULL; + HDC mhDCThrd = 0; // *HACK: Attempt to prevent startup crashes by deferring memory accounting // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 @@ -992,53 +996,10 @@ void LLWindowWin32::close() LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; - mWindowThread->post([=]() - { - if (IsWindow(mWindowHandle)) - { - if (mhDC) - { - if (!ReleaseDC(mWindowHandle, mhDC)) - { - LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL; - } - } - - // Make sure we don't leave a blank toolbar button. - ShowWindow(mWindowHandle, SW_HIDE); - - // This causes WM_DESTROY to be sent *immediately* - if (!destroy_window_handler(mWindowHandle)) - { - // Can't use a message box here because we're about to stop servicing the events. - // OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), - // mCallbacks->translateString("MBShutdownErr"), - // OSMB_OK); - LL_INFOS("Window") << "Destroying Window failed" << LL_ENDL; - // - } - } - else - { - // Something killed the window while we were busy destroying gl or handle somehow got broken - LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; - } - - }); - // Window thread might be waiting for a getMessage(), give it - // a push to enshure it will process destroy_window_handler - kickWindowThread(); - - // Even though the above lambda might not yet have run, we've already - // bound mWindowHandle into it by value, which should suffice for the - // operations we're asking. That's the last time WE should touch it. mhDC = NULL; mWindowHandle = NULL; - // [FIRE-32453][BUG-232971] close the related queues first to prevent spinning. - mFunctionQueue.close(); - mMouseQueue.close(); - // - mWindowThread->close(); + + mWindowThread->wakeAndDestroy(); } BOOL LLWindowWin32::isValid() @@ -1791,8 +1752,8 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw () { LL_DEBUGS("Window") << "recreateWindow(): window_work entry" << LL_ENDL; - self->mWindowHandle = 0; - self->mhDC = 0; + self->mWindowHandleThrd = 0; + self->mhDCThrd = 0; if (oldWindowHandle) { @@ -1826,20 +1787,20 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw { // Failed to create window: clear the variables. This // assignment is valid because we're running on mWindowThread. - self->mWindowHandle = NULL; - self->mhDC = 0; + self->mWindowHandleThrd = NULL; + self->mhDCThrd = 0; } else { // Update mWindowThread's own mWindowHandle and mhDC. - self->mWindowHandle = handle; - self->mhDC = GetDC(handle); + self->mWindowHandleThrd = handle; + self->mhDCThrd = GetDC(handle); } updateWindowRect(); // It's important to wake up the future either way. - promise.set_value(std::make_pair(self->mWindowHandle, self->mhDC)); + promise.set_value(std::make_pair(self->mWindowHandleThrd, self->mhDCThrd)); LL_DEBUGS("Window") << "recreateWindow(): window_work done" << LL_ENDL; }; // But how we pass window_work to the window thread depends on whether we @@ -3723,6 +3684,7 @@ void LLWindowWin32::swapBuffers() } } + // // LLSplashScreenImp // @@ -3745,6 +3707,9 @@ void LLSplashScreenWin32::showImpl() NULL, // no parent (DLGPROC) LLSplashScreenWin32::windowProc); ShowWindow(mWindow, SW_SHOW); + + // Should set taskbar text without creating a header for the window (caption) + SetWindowTextA(mWindow, APP_NAME.c_str()); } @@ -4708,11 +4673,25 @@ void LLWindowWin32::getWindowChrome( U32 &aChromeW, U32 &aChromeH ) #endif // LL_WINDOWS inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() - : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE) + : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, true /*should be false, temporary workaround for SL-18721*/) { LL::ThreadPool::start(); } +void LLWindowWin32::LLWindowWin32Thread::close() +{ + if (!mQueue->isClosed()) + { + LL_WARNS() << "Closing window thread without using destroy_window_handler" << LL_ENDL; + LL::ThreadPool::close(); + + // Workaround for SL-18721 in case window closes too early and abruptly + LLSplashScreen::show(); + LLSplashScreen::update("..."); // will be updated later + } +} + + /** * LogChange is to log changes in status while trying to avoid spamming the * log with repeated messages, especially in a tight loop. It refuses to log @@ -4864,7 +4843,7 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D() { if (!mGLReady) { return; } - if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandle != 0) + if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandleThrd != 0) { mD3D = Direct3DCreate9(D3D_SDK_VERSION); @@ -4874,7 +4853,7 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D() d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; - HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice); + HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandleThrd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice); if (FAILED(res)) { @@ -4887,6 +4866,28 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D() } } +void LLWindowWin32::LLWindowWin32Thread::cleanupDX() +{ + //clean up DXGI/D3D resources + if (mDXGIAdapter) + { + mDXGIAdapter->Release(); + mDXGIAdapter = nullptr; + } + + if (mD3DDevice) + { + mD3DDevice->Release(); + mD3DDevice = nullptr; + } + + if (mD3D) + { + mD3D->Release(); + mD3D = nullptr; + } +} + void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage() { LL_PROFILE_ZONE_SCOPED; @@ -4960,45 +4961,10 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage() } } -// [FIRE-32453][BUG-232971] Improve shutdown behaviour. -// Provide a close() override that ignores the initial close triggered by the threadpool detecting "quit" -// but waits for the viewer to be disconected and the second close call triggered by the app window destructor -void LLWindowWin32::LLWindowWin32Thread::close() -{ - assert_main_thread(); - if (!mQueue->isClosed() && gDisconnected) - { - LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL; - mQueue->close(); - for (auto& pair: mThreads) - { - LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL; - // As we cannot seem to rely on the clean and timely exit of the windows thread in ALL situations we apply a timeout. - std::future f = std::async(std::launch::async, [&] { pair.second.join(); }); - if (f.wait_until(std::chrono::steady_clock::now() + std::chrono::seconds(5)) == std::future_status::ready) { - LL_DEBUGS("ThreadPool") << mName << " joined normally." << LL_ENDL; - } else { - LL_WARNS("ThreadPool") << mName << " join timed out." << LL_ENDL; - // the specified time point was reached before the thread finished execution and could be joined - } - } - LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL; - } - else - { - LL_DEBUGS("ThreadPool") << mName << " shutdown request ignored - not yet disconneced." << LL_ENDL; - } -} -// - void LLWindowWin32::LLWindowWin32Thread::run() { sWindowThreadId = std::this_thread::get_id(); LogChange logger("Window"); - // [FIRE-32453][BUG-232971] Improve shutdown behaviour. - try - { - // //as good a place as any to up the MM timer resolution (see ms_sleep) //attempt to set timer resolution to 1ms TIMECAPS tc; @@ -5014,7 +4980,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() // lazily call initD3D inside this loop to catch when mGLReady has been set to true initDX(); - if (mWindowHandle != 0) + if (mWindowHandleThrd != 0) { // lazily call initD3D inside this loop to catch when mWindowHandle has been set, and mGLReady has been set to true // *TODO: Shutdown if this fails when mWindowHandle exists @@ -5022,16 +4988,16 @@ void LLWindowWin32::LLWindowWin32Thread::run() MSG msg; BOOL status; - if (mhDC == 0) + if (mhDCThrd == 0) { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - PeekMessage"); - logger.onChange("PeekMessage(", std::hex, mWindowHandle, ")"); - status = PeekMessage(&msg, mWindowHandle, 0, 0, PM_REMOVE); + logger.onChange("PeekMessage(", std::hex, mWindowHandleThrd, ")"); + status = PeekMessage(&msg, mWindowHandleThrd, 0, 0, PM_REMOVE); } else { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - GetMessage"); - logger.always("GetMessage(", std::hex, mWindowHandle, ")"); + logger.always("GetMessage(", std::hex, mWindowHandleThrd, ")"); status = GetMessage(&msg, NULL, 0, 0); } if (status > 0) @@ -5040,21 +5006,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() ", ", msg.wParam, ")"); TranslateMessage(&msg); DispatchMessage(&msg); - // [FIRE-32453][BUG-232971] Improve shutdown behaviour. - // mMessageQueue.pushFront(msg); - try - { - // Nobody is reading this queue once we are quitting. Writing to it causes a hang. - if(!LLApp::isQuitting()) - mMessageQueue.pushFront(msg); - } - catch (const LLThreadSafeQueueInterrupt&) - { - // Shutdown timing is tricky. The main thread can end up trying - // to post a cursor position after having closed the WorkQueue. - logger.always("Message procesing tried to push() to closed MessageQueue - caught"); - } - // + mMessageQueue.pushFront(msg); } } @@ -5080,38 +5032,111 @@ void LLWindowWin32::LLWindowWin32Thread::run() } #endif } - // [FIRE-32453][BUG-232971] Improve shutdown behaviour. - } - catch (const std::exception& e) - { - logger.always("Windows thread exiting - Exception: ", e.what()); - } - catch (...) - { - logger.always("Windows thread exiting - Exception: Unknown"); - } - logger.always("done - queue closed on windows thread."); - // - //clean up DXGI/D3D resources - if (mDXGIAdapter) + cleanupDX(); +} + +void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() +{ + if (mQueue->isClosed()) { - mDXGIAdapter->Release(); - mDXGIAdapter = nullptr; + LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; + return; } - if (mD3DDevice) + // Make sure we don't leave a blank toolbar button. + // Also hiding window now prevents user from suspending it + // via some action (like dragging it around) + ShowWindow(mWindowHandleThrd, SW_HIDE); + + // Schedule destruction + HWND old_handle = mWindowHandleThrd; + post([this]() + { + if (IsWindow(mWindowHandleThrd)) + { + if (mhDCThrd) + { + if (!ReleaseDC(mWindowHandleThrd, mhDCThrd)) + { + LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL; + } + mhDCThrd = NULL; + } + + // This causes WM_DESTROY to be sent *immediately* + if (!destroy_window_handler(mWindowHandleThrd)) + { + LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL; + } + } + else + { + // Something killed the window while we were busy destroying gl or handle somehow got broken + LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; + } + mWindowHandleThrd = NULL; + mhDCThrd = NULL; + mGLReady = false; + }); + + LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL; + mQueue->close(); + + // Post a nonsense user message to wake up the thread in + // case it is waiting for a getMessage() + if (old_handle) { - mD3DDevice->Release(); - mD3DDevice = nullptr; + WPARAM wparam{ 0xB0B0 }; + LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle + << ", " << WM_DUMMY_ + << ", " << wparam << ")" << std::dec << LL_ENDL; + PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); } - if (mD3D) + // There are cases where window will refuse to close, + // can't wait forever on join, check state instead + LLTimer timeout; + timeout.setTimerExpirySec(2.0); + while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd) { - mD3D->Release(); - mD3D = nullptr; + ms_sleep(100); } + if (getQueue().done() || mWindowHandleThrd == NULL) + { + // Window is closed, started closing or is cleaning up + // now wait for our single thread to die. + if (mWindowHandleThrd) + { + LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; + } + else + { + LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; + } + for (auto& pair : mThreads) + { + pair.second.join(); + } + } + else + { + // Something suspended window thread, can't afford to wait forever + // so kill thread instead + // Ex: This can happen if user starts dragging window arround (if it + // was visible) or a modal notification pops up + LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL; + + for (auto& pair : mThreads) + { + // very unsafe + TerminateThread(pair.second.native_handle(), 0); + pair.second.detach(); + cleanupDX(); + } + } + LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL; } void LLWindowWin32::post(const std::function& func) diff --git a/indra/media_plugins/cef/linux_volume_catcher.cpp b/indra/media_plugins/cef/linux_volume_catcher.cpp index 43773bb952..6e7691ff57 100755 --- a/indra/media_plugins/cef/linux_volume_catcher.cpp +++ b/indra/media_plugins/cef/linux_volume_catcher.cpp @@ -286,7 +286,11 @@ void VolumeCatcherImpl::setVolume(F32 volume) void VolumeCatcherImpl::pump() { - return; + // PR#17 makidoll: Fix Linux volume catcher + if (mGotSyms && mMainloop) { + llpa_mainloop_iterate(mMainloop, 0, NULL); + } + // } void VolumeCatcherImpl::connected_okay() diff --git a/indra/media_plugins/cef/linux_volume_catcher_pa_syms.inc b/indra/media_plugins/cef/linux_volume_catcher_pa_syms.inc index 2c9f760fba..4e65221003 100755 --- a/indra/media_plugins/cef/linux_volume_catcher_pa_syms.inc +++ b/indra/media_plugins/cef/linux_volume_catcher_pa_syms.inc @@ -21,5 +21,6 @@ LL_PA_SYM(true, pa_sw_volume_from_linear, pa_volume_t, double v); LL_PA_SYM(true, pa_mainloop_free, void, pa_mainloop* m); LL_PA_SYM(true, pa_mainloop_get_api, pa_mainloop_api*, pa_mainloop* m); LL_PA_SYM(true, pa_mainloop_new, pa_mainloop*, void); +LL_PA_SYM(true, pa_mainloop_iterate, int, pa_mainloop*, int, int*); // optional symbols to grab diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 570acac23b..a73103f668 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -152,6 +152,7 @@ set(viewer_SOURCE_FILES fsnearbychatvoicemonitor.cpp fspanelblocklist.cpp fspanelcontactsets.cpp + fspanelface.cpp fspanelimcontrolpanel.cpp fspanellogin.cpp fspanelprefs.cpp @@ -944,6 +945,7 @@ set(viewer_HEADER_FILES fsnearbychatvoicemonitor.h fspanelblocklist.h fspanelcontactsets.h + fspanelface.h fspanelimcontrolpanel.h fspanellogin.h fspanelprefs.h diff --git a/indra/newview/Info-Firestorm.plist b/indra/newview/Info-Firestorm.plist index 2b0e24e92e..6b2e73a5a2 100644 --- a/indra/newview/Info-Firestorm.plist +++ b/indra/newview/Info-Firestorm.plist @@ -28,6 +28,8 @@ ${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION} CSResourcesFileMapped + LSApplicationCategoryType + public.app-category.games LSRequiresCarbon NSAppSleepDisabled diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index b7f8ee41e6..14627a7c8c 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -7.1.4 +7.1.6 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7ba854ef54..85634bc3ec 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5152,171 +5152,6 @@ Value -1 - DebugStatModeMemTrace - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemUI - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemFonts - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemInventory - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemObjects - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemOctreeGroupData - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemOctreeData - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemObjectCache - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemDrawable - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemFaceData - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemDrawInfo - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemTextureData - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemImageData - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemGLImageData - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - - DebugStatModeMemVertexBuffer - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - DebugStatModeMaterials Comment @@ -5354,17 +5189,6 @@ Backup 0 - DefaultBlankNormalTexture - - Comment - Texture used as 'Blank' in texture picker for normal maps. (UUID texture reference) - Persist - 1 - Type - String - Value - 5b53359e-59dd-d8a2-04c3-9e65134da47a - DefaultFemaleAvatar Comment @@ -5398,39 +5222,6 @@ Value Male Shape & Outfit - DefaultObjectNormalTexture - - Comment - Texture used as 'Default' in texture picker for normal map. (UUID texture reference) - Persist - 1 - Type - String - Value - 85f28839-7a1c-b4e3-d71d-967792970a7b - - DefaultObjectSpecularTexture - - Comment - Texture used as 'Default' in texture picker for specular map. (UUID texture reference) - Persist - 1 - Type - String - Value - 87e0e8f7-8729-1ea8-cfc9-8915773009db - - DefaultObjectTexture - - Comment - Texture used as 'Default' in texture picker. (UUID texture reference) - Persist - 1 - Type - String - Value - 89556747-24cb-43ed-920b-47caed15465f - DefaultUploadCost Comment @@ -7776,6 +7567,17 @@ Backup 0 + LSLFontSizeName + + Comment + UNUSED - Text font size in LSL editor + Persist + 1 + Type + String + Value + Monospace + GridStatusRSS Comment @@ -10386,21 +10188,10 @@ Change of this parameter will affect the layout of buttons in notification toast Value 1 - OpenDebugStatAdvanced - - Comment - Expand advanced performance stats display - Persist - 1 - Type - Boolean - Value - 1 - OpenDebugStatBasic Comment - Expand basic performance stats display + Expand Basic performance stats display Persist 1 Type @@ -10408,10 +10199,10 @@ Change of this parameter will affect the layout of buttons in notification toast Value 1 - OpenDebugStatNet + OpenDebugStatAdvanced Comment - Expand network stats display + Expand Advanced performance stats display Persist 1 Type @@ -10422,18 +10213,7 @@ Change of this parameter will affect the layout of buttons in notification toast OpenDebugStatRender Comment - Expand render stats display - Persist - 1 - Type - Boolean - Value - 1 - - OpenDebugStatSim - - Comment - Expand simulator performance stats display + Expand Render performance stats display Persist 1 Type @@ -10452,10 +10232,32 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 - OpenDebugStatSimPathfinding + OpenDebugStatNet Comment - Expand Pathfinding performance stats display + Expand Network performance stats display + Persist + 1 + Type + Boolean + Value + 1 + + OpenDebugStatSim + + Comment + Expand Simulator performance stats display + Persist + 1 + Type + Boolean + Value + 1 + + OpenDebugStatPhysicsDetails + + Comment + Expand Physics Details performance stats display Persist 1 Type @@ -10463,10 +10265,10 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 - OpenDebugStatPhysicsDetails + OpenDebugStatPathfinding Comment - Expand Physics Details performance stats display + Expand Pathfinding performance stats display Persist 1 Type @@ -10496,17 +10298,6 @@ Change of this parameter will affect the layout of buttons in notification toast Value 1 - OpenDebugStatMemory - - Comment - Expand Memory performance stats display - Persist - 1 - Type - Boolean - Value - 1 - OutBandwidth Comment @@ -13787,7 +13578,7 @@ Change of this parameter will affect the layout of buttons in notification toast Type F32 Value - 2.0 + 1.0 RendeSkyAutoAdjustBlueHorizonScale @@ -13831,7 +13622,7 @@ Change of this parameter will affect the layout of buttons in notification toast Type F32 Value - 0.001 + 0.01 RenderSkySunlightScale @@ -16846,17 +16637,6 @@ Change of this parameter will affect the layout of buttons in notification toast Value F3E07BC8-A973-476D-8C7F-F3B7293975D1 - UIImgWhiteUUID - - Comment - - Persist - 0 - Type - String - Value - 5748decc-f629-461c-9a36-a35a221fe21f - UIImgTransparentUUID Comment @@ -18172,6 +17952,21 @@ Change of this parameter will affect the layout of buttons in notification toast Backup 0 + FSShowSelectedInBlinnPhong + + Comment + Show BlinnPhong while selected (non-persistent).This setting is driven by the code, not by user + Persist + 0 + Type + Boolean + Value + 0 + Backup + 0 + HideFromEditor + 1 + ShowSpecificLODInEdit Comment @@ -21791,17 +21586,6 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 - FSDisplaySavedOutfitsCap - - Comment - Display only so many saved outfits in edit appearance. 0 to disable. - Persist - 1 - Type - U32 - Value - 0 - FSAdvancedWorldmapRegionInfo Comment @@ -25000,17 +24784,6 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 - VoiceMultiInstance - - Comment - Enables using voice in multiple simultaneous viewer instances - Persist - 1 - Type - Boolean - Value - 1 - FSSoundCacheLocation Comment @@ -26792,5 +26565,57 @@ Change of this parameter will affect the layout of buttons in notification toast Value 128578 - + FSUseNewTexturePanel + + Backup + 1 + Comment + Use the new Texture/Material editor panel in build mode + Persist + 1 + Type + Boolean + Value + 1 + + FSInternalCanEditObjectFaces + + Comment + Internal control to show/hide object texture/material edit controls + HideFromEditor + 1 + Persist + 0 + Type + Boolean + Value + 1 + + FSInternalFaceHasBPNormalMap + + Comment + Internal control to store a flag about the edited face having a Blinn-Phong normal map or not + HideFromEditor + 1 + Persist + 0 + Type + Boolean + Value + 1 + + FSInternalFaceHasBPSpecularMap + + Comment + Internal control to store a flag about the edited face having a Blinn-Phong specular map or not + HideFromEditor + 1 + Persist + 0 + Type + Boolean + Value + 1 + + diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index ed9a8240e4..243b17cf73 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -2023,7 +2023,7 @@ value_min="-1" value_max="1"> - + - - - @@ -2044,7 +2043,7 @@ name="mFaceEyeAltRight" scale="0 0 0" offset="-.005 0 0" /> - + - @@ -2064,17 +2063,17 @@ name="mFaceEyeLidUpperLeft" scale="0 0.3 0.7" offset=" 0 0 0" /> - + - + - + diff --git a/indra/newview/fscommon.cpp b/indra/newview/fscommon.cpp index b4421c4ae9..bc40a832b0 100644 --- a/indra/newview/fscommon.cpp +++ b/indra/newview/fscommon.cpp @@ -478,7 +478,8 @@ bool FSCommon::isDefaultTexture(const LLUUID& asset_id) asset_id == LL_DEFAULT_PLASTIC_UUID || asset_id == LL_DEFAULT_RUBBER_UUID || asset_id == LL_DEFAULT_LIGHT_UUID || - asset_id == LLUUID("5748decc-f629-461c-9a36-a35a221fe21f") || // UIImgWhiteUUID + asset_id == IMG_WHITE || + asset_id == LLUUID("5748decc-f629-461c-9a36-a35a221fe21f") || // UIImgWhiteUUID (legacy: replaced by IMG_WHITE) asset_id == LLUUID("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903") || // UIImgTransparentUUID asset_id == LLUUID("f54a0c32-3cd1-d49a-5b4f-7b792bebc204") || // UIImgInvisibleUUID asset_id == LLUUID("6522e74d-1660-4e7f-b601-6f48c1659a77") || // UIImgDefaultEyesUUID diff --git a/indra/newview/fsfloaterwearablefavorites.cpp b/indra/newview/fsfloaterwearablefavorites.cpp index cd632b70d2..f95c238ec0 100644 --- a/indra/newview/fsfloaterwearablefavorites.cpp +++ b/indra/newview/fsfloaterwearablefavorites.cpp @@ -311,7 +311,7 @@ void FSFloaterWearableFavorites::handleRemove() void FSFloaterWearableFavorites::onFilterEdit(const std::string& search_string) { - mItemsList->setFilterSubString(search_string); + mItemsList->setFilterSubString(search_string, true); mItemsList->setNoItemsCommentText(getString("empty_list")); } diff --git a/indra/newview/fspanelface.cpp b/indra/newview/fspanelface.cpp new file mode 100644 index 0000000000..a28e658892 --- /dev/null +++ b/indra/newview/fspanelface.cpp @@ -0,0 +1,5961 @@ +/** + * @file fspanelface.cpp + * @brief Consolidated materials/texture panel in the tools floater + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2024, Zi Ree@Second Life + * + * 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 "fspanelface.h" + +#include // Used to find all faces with same texture + +#include "llagent.h" +#include "llagentdata.h" +#include "llbutton.h" +#include "llcalc.h" +#include "llcheckboxctrl.h" +#include "llcolorswatch.h" +#include "llcombobox.h" +#include "lldrawpoolbump.h" +#include "llerror.h" +#include "llface.h" +// #include "llfilesystem.h" +#include "llfetchedgltfmaterial.h" +#include "llgltfmateriallist.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" // gInventory +#include "llinventorymodelbackgroundfetch.h" +#include "llfloatermediasettings.h" +#include "llfloaterreg.h" +#include "llfloatertools.h" +#include "llfontgl.h" +#include "lllineeditor.h" +#include "llmaterialmgr.h" +#include "llmaterialeditor.h" +#include "llmediactrl.h" +#include "llmediaentry.h" +#include "llmenubutton.h" +#include "llnotificationsutil.h" +#include "llpanelcontents.h" +#include "llpluginclassmedia.h" +#include "llradiogroup.h" +#include "llrect.h" +#include "llresmgr.h" +// #include "llsd.h" +// #include "llsdserialize.h" +// #include "llsdutil.h" +#include "llselectmgr.h" +#include "llspinctrl.h" +#include "llstring.h" +#include "lltextbox.h" +#include "lltexturectrl.h" +#include "lltextureentry.h" +#include "lltooldraganddrop.h" +#include "lltoolface.h" +#include "lltoolmgr.h" +#include "lltrans.h" +#include "llui.h" +// #include "llviewerassetupload.h" +#include "llviewercontrol.h" +#include "llviewermedia.h" +// #include "llviewermenufile.h" +#include "llviewerobject.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llvovolume.h" +#include "llvoinventorylistener.h" +#include "lluictrlfactory.h" +#include "llviewertexturelist.h"// Update sel manager as to which channel we're editing so it can reflect the correct overlay UI + +// Dirty flags - taken from llmaterialeditor.cpp ... LL please put this in a .h! -Zi +static const U32 MATERIAL_BASE_COLOR_DIRTY = 0x1 << 0; +static const U32 MATERIAL_BASE_COLOR_TEX_DIRTY = 0x1 << 1; + +static const U32 MATERIAL_NORMAL_TEX_DIRTY = 0x1 << 2; + +static const U32 MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY = 0x1 << 3; +static const U32 MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY = 0x1 << 4; +static const U32 MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY = 0x1 << 5; + +static const U32 MATERIAL_EMISIVE_COLOR_DIRTY = 0x1 << 6; +static const U32 MATERIAL_EMISIVE_TEX_DIRTY = 0x1 << 7; + +static const U32 MATERIAL_DOUBLE_SIDED_DIRTY = 0x1 << 8; +static const U32 MATERIAL_ALPHA_MODE_DIRTY = 0x1 << 9; +static const U32 MATERIAL_ALPHA_CUTOFF_DIRTY = 0x1 << 10; + +FSPanelFace::Selection FSPanelFace::sMaterialOverrideSelection; + +void FSPanelFace::updateSelectedGLTFMaterials(std::function func) +{ + struct LLSelectedTEGLTFMaterialFunctor : public LLSelectedTEFunctor + { + LLSelectedTEGLTFMaterialFunctor(std::function func) : mFunc(func) {} + virtual ~LLSelectedTEGLTFMaterialFunctor() {}; + bool apply(LLViewerObject* object, S32 face) override + { + LLGLTFMaterial new_override; + const LLTextureEntry* tep = object->getTE(face); + if (tep->getGLTFMaterialOverride()) + { + new_override = *tep->getGLTFMaterialOverride(); + } + mFunc(&new_override); + LLGLTFMaterialList::queueModify(object, face, &new_override); + + return true; + } + + std::function mFunc; + } select_func(func); + + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&select_func); +} + +template +void readSelectedGLTFMaterial(std::function func, T& value, bool& identical, bool has_tolerance, T tolerance) +{ + struct LLSelectedTEGetGLTFMaterialFunctor : public LLSelectedTEGetFunctor + { + LLSelectedTEGetGLTFMaterialFunctor(std::function func) : mFunc(func) {} + virtual ~LLSelectedTEGetGLTFMaterialFunctor() {}; + T get(LLViewerObject* object, S32 face) override + { + const LLTextureEntry* tep = object->getTE(face); + const LLGLTFMaterial* render_material = tep->getGLTFRenderMaterial(); + + return mFunc(render_material); + } + + std::function mFunc; + } select_func(func); + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&select_func, value, has_tolerance, tolerance); +} + +// +// keep LLRenderMaterialFunctor in sync with llmaterialeditor.cpp - Would be nice if we +// had this in its own file so we could include it from both sides ... -Zi +// + +// local preview of material changes +class LLRenderMaterialFunctor : public LLSelectedTEFunctor +{ +public: + LLRenderMaterialFunctor(const LLUUID &id) + : mMatId(id) + { + } + + bool apply(LLViewerObject* objectp, S32 te) override + { + if (objectp && objectp->permModify() && objectp->getVolume()) + { + LLVOVolume* vobjp = (LLVOVolume*)objectp; + vobjp->setRenderMaterialID(te, mMatId, false /*preview only*/); + vobjp->updateTEMaterialTextures(te); + } + return true; + } +private: + LLUUID mMatId; +}; + +// +// keep LLRenderMaterialOverrideFunctor in sync with llmaterialeditor.cpp just take +// out the reverting functionality as it makes no real sense with all the texture +// controls visible for the material at all times. +// TODO: look at how to handle local textures, especially when saving materials +// - Would be nice if we had this in its own file so we could include it from both sides ... -Zi +// +class LLRenderMaterialOverrideFunctor : public LLSelectedNodeFunctor +{ +public: + LLRenderMaterialOverrideFunctor( + LLGLTFMaterial* material_to_apply, + U32 unsaved_changes + ) + : mMaterialToApply(material_to_apply) + , mUnsavedChanges(unsaved_changes) + { + } + + virtual bool apply(LLSelectNode* nodep) override + { + LLViewerObject* objectp = nodep->getObject(); + if (!objectp || !objectp->permModify() || !objectp->getVolume()) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10001 << " skipped object" << LL_ENDL; + return false; + } + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); // avatars have TEs but no faces + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10002 << " " << num_tes << LL_ENDL; + + // post override from given object and te to the simulator + // requestData should have: + // object_id - UUID of LLViewerObject + // side - S32 index of texture entry + // gltf_json - String of GLTF json for override data + + for (S32 te = 0; te < num_tes; ++te) + { + if (!nodep->isTESelected(te)) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10003 << " skipping unselected te " << te << LL_ENDL; + continue; + } + + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10004 << " te " << te << LL_ENDL; + // Get material from object + // Selection can cover multiple objects, and live editor is + // supposed to overwrite changed values only + LLTextureEntry* tep = objectp->getTE(te); + + if (tep->getGLTFMaterial() == nullptr) + { + // overrides are not supposed to work or apply if + // there is no base material to work from + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10004 << " skipping te with no base material " << te << LL_ENDL; + continue; + } + + LLPointer material = tep->getGLTFMaterialOverride(); + LL_DEBUGS("APPLY_GLTF_CHANGES") << "10004b" << " material is null? " << material.isNull() << LL_ENDL; + // make a copy to not invalidate existing + // material for multiple objects + if (material.isNull()) + { + // Start with a material override which does not make any changes + material = new LLGLTFMaterial(); + } + else + { + material = new LLGLTFMaterial(*material); + } + + // Override object's values with values from editor where appropriate + if (mUnsavedChanges & MATERIAL_BASE_COLOR_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_BASE_COLOR_DIRTY" << LL_ENDL; + material->setBaseColorFactor(mMaterialToApply->mBaseColor, true); + } + + if (mUnsavedChanges & MATERIAL_BASE_COLOR_TEX_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_BASE_COLOR_TEX_DIRTY" << LL_ENDL; + material->setBaseColorId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR], true); + /* + LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_BASE_COLOR_TEX_DIRTY); + if (tracking_id.notNull()) + { + LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material); + } + */ + } + + if (mUnsavedChanges & MATERIAL_NORMAL_TEX_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_NORMAL_TEX_DIRTY" << LL_ENDL; + material->setNormalId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL], true); + /* + LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_NORMAL_TEX_DIRTY); + if (tracking_id.notNull()) + { + LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material); + } + */ + } + + if (mUnsavedChanges & MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY" << LL_ENDL; + material->setOcclusionRoughnessMetallicId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS], true); + /* + LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY); + if (tracking_id.notNull()) + { + LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material); + } + */ + } + + if (mUnsavedChanges & MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY" << LL_ENDL; + material->setMetallicFactor(mMaterialToApply->mMetallicFactor, true); + } + + if (mUnsavedChanges & MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY" << LL_ENDL; + material->setRoughnessFactor(mMaterialToApply->mRoughnessFactor, true); + } + + if (mUnsavedChanges & MATERIAL_EMISIVE_COLOR_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_EMISIVE_COLOR_DIRTY" << LL_ENDL; + material->setEmissiveColorFactor(LLColor3(mMaterialToApply->mEmissiveColor), true); + } + + if (mUnsavedChanges & MATERIAL_EMISIVE_TEX_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_EMISIVE_TEX_DIRTY" << LL_ENDL; + material->setEmissiveId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE], true); + /* + LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_EMISIVE_TEX_DIRTY); + if (tracking_id.notNull()) + { + LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material); + } + */ + } + + if (mUnsavedChanges & MATERIAL_DOUBLE_SIDED_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_DOUBLE_SIDED_DIRTY" << LL_ENDL; + material->setDoubleSided(mMaterialToApply->mDoubleSided, true); + } + + if (mUnsavedChanges & MATERIAL_ALPHA_MODE_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_ALPHA_MODE_DIRTY" << LL_ENDL; + material->setAlphaMode(mMaterialToApply->mAlphaMode, true); + } + + if (mUnsavedChanges & MATERIAL_ALPHA_CUTOFF_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_ALPHA_CUTOFF_DIRTY" << LL_ENDL; + material->setAlphaCutoff(mMaterialToApply->mAlphaCutoff, true); + } + + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10100 << " queueing material update " << te << LL_ENDL; + LLGLTFMaterialList::queueModify(objectp, te, material); + } + return true; + } + +private: + LLGLTFMaterial* mMaterialToApply; + U32 mUnsavedChanges; +}; + +// +// Get all material parameters +// +struct LLSelectedTEGetmatId : public LLSelectedTEFunctor +{ + LLSelectedTEGetmatId() : + mHasFacesWithoutPBR(false), + mHasFacesWithPBR(false), + mInitialized(false), + mMaterial(nullptr) + { + } + + bool apply(LLViewerObject* object, S32 te_index) override + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "object " << object << " te_index " << te_index << LL_ENDL; + LLUUID pbr_id = object->getRenderMaterialID(te_index); + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000000 << " Material: " << pbr_id << LL_ENDL; + + if (pbr_id.isNull()) + { + mHasFacesWithoutPBR = true; + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000001 << LL_ENDL; + return false; + } + + mHasFacesWithPBR = true; + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000002 << LL_ENDL; + + if (mInitialized) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000003 << LL_ENDL; + if (mMaterialId != pbr_id) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000004 << LL_ENDL; + mIdenticalMaterial = false; + } + + LLGLTFMaterial* te_mat = object->getTE(te_index)->getGLTFMaterial(); + LLGLTFMaterial* te_override = object->getTE(te_index)->getGLTFMaterialOverride(); + + // copy base material values to the override material, so we can apply the override to it in the next steps + if (te_mat) + { + mMaterialOverride = *te_mat; + } + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000005 << " te_override:" << te_override << LL_ENDL; + for(U32 map = 0; map < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; map++) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000009 << " map:" << map << LL_ENDL; + + LLUUID texture_map_id; + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000018 << "te_mat:" << te_mat << " mMaterialOverride.mTextureId[map]:" << mMaterialOverride.mTextureId[map] << LL_ENDL; + texture_map_id = mMaterialOverride.mTextureId[map]; + + if (te_override) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "10000018b" << " te_override->mTextureId[map]:" << te_override->mTextureId[map] << LL_ENDL; + if (te_override->mTextureId[map].notNull()) + { + texture_map_id = te_override->mTextureId[map]; + if (texture_map_id == LLGLTFMaterial::GLTF_OVERRIDE_NULL_UUID) + { + texture_map_id.setNull(); + } + } + } + + if (texture_map_id != mMaterialSummary.mTextureId[map]) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000018 << " mIdenticalMap[" << map << "]: false" << LL_ENDL; + mIdenticalMap[map] = false; + } + } + + if (te_override) + { + // copy values from base material to the override where the override has defaults + if (te_override->mBaseColor == LLGLTFMaterial::getDefaultBaseColor()) mMaterialOverride.mBaseColor = te_mat->mBaseColor; + if (te_override->mMetallicFactor == LLGLTFMaterial::getDefaultMetallicFactor()) mMaterialOverride.mMetallicFactor = te_mat->mMetallicFactor; + if (te_override->mRoughnessFactor == LLGLTFMaterial::getDefaultRoughnessFactor()) mMaterialOverride.mRoughnessFactor = te_mat->mRoughnessFactor; + if (te_override->mEmissiveColor == LLGLTFMaterial::getDefaultEmissiveColor()) mMaterialOverride.mEmissiveColor = te_mat->mEmissiveColor; + if (te_override->mDoubleSided == LLGLTFMaterial::getDefaultDoubleSided()) mMaterialOverride.mDoubleSided = te_mat->mDoubleSided; + if (te_override->mAlphaMode == LLGLTFMaterial::getDefaultAlphaMode()) mMaterialOverride.mAlphaMode = te_mat->mAlphaMode; + if (te_override->mAlphaCutoff == LLGLTFMaterial::getDefaultAlphaCutoff()) mMaterialOverride.mAlphaCutoff = te_mat->mAlphaCutoff; + } + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "10000018c" << " te_mat->mEmissiveColor:" << te_mat->mEmissiveColor << LL_ENDL; + + if (mMaterialOverride.mBaseColor != mMaterialSummary.mBaseColor) mIdenticalBaseColor = false; + if (mMaterialOverride.mMetallicFactor != mMaterialSummary.mMetallicFactor) mIdenticalMetallic = false; + if (mMaterialOverride.mRoughnessFactor != mMaterialSummary.mRoughnessFactor) mIdenticalRoughness = false; + if (mMaterialOverride.mEmissiveColor != mMaterialSummary.mEmissiveColor) mIdenticalEmissive = false; + if (mMaterialOverride.mDoubleSided != mMaterialSummary.mDoubleSided) mIdenticalDoubleSided = false; + if (mMaterialOverride.mAlphaMode != mMaterialSummary.mAlphaMode) mIdenticalAlphaMode = false; + if (mMaterialOverride.mAlphaCutoff != mMaterialSummary.mAlphaCutoff) mIdenticalAlphaCutoff = false; + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000011 << LL_ENDL; + } + else + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000012 << LL_ENDL; + + mIdenticalMaterial = true; + mIdenticalBaseColor = true; + mIdenticalMetallic = true; + mIdenticalRoughness = true; + mIdenticalEmissive = true; + mIdenticalDoubleSided = true; + mIdenticalAlphaMode = true; + mIdenticalAlphaCutoff = true; + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000013 << LL_ENDL; + + LLGLTFMaterial* mat = object->getTE(te_index)->getGLTFMaterial(); + LLGLTFMaterial* override = object->getTE(te_index)->getGLTFMaterialOverride(); + + mMaterialId = pbr_id; + mMaterial = override; + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000014 << " override:" << override << LL_ENDL; + + // copy base material values to the "summary" material, so we can apply the override to it in the next step + if (mat) + { + mMaterialSummary = *mat; + } + + for(U32 map = 0; map < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; map++) + { + // initialize array to say "all PBR maps are the same" + mIdenticalMap[map] = true; + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000017 << " map:" << map << LL_ENDL; + + if (override && override->mTextureId[map].notNull()) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "10000017b" << " override->mTextureId[map]:" << override->mTextureId[map] << LL_ENDL; + if (override->mTextureId[map] == LLGLTFMaterial::GLTF_OVERRIDE_NULL_UUID) + { + mMaterialSummary.mTextureId[map].setNull(); + } + else + { + mMaterialSummary.mTextureId[map] = override->mTextureId[map]; + } + } + } + + if (override) + { + // copy values from override to the "summary" material where the override differs from the default + if (override->mBaseColor != LLGLTFMaterial::getDefaultBaseColor()) mMaterialSummary.mBaseColor = override->mBaseColor; + if (override->mMetallicFactor != LLGLTFMaterial::getDefaultMetallicFactor()) mMaterialSummary.mMetallicFactor = override->mMetallicFactor; + if (override->mRoughnessFactor != LLGLTFMaterial::getDefaultRoughnessFactor()) mMaterialSummary.mRoughnessFactor = override->mRoughnessFactor; + if (override->mEmissiveColor != LLGLTFMaterial::getDefaultEmissiveColor()) mMaterialSummary.mEmissiveColor = override->mEmissiveColor; + if (override->mDoubleSided != LLGLTFMaterial::getDefaultDoubleSided()) mMaterialSummary.mDoubleSided = override->mDoubleSided; + if (override->mAlphaMode != LLGLTFMaterial::getDefaultAlphaMode()) mMaterialSummary.setAlphaMode(override->getAlphaMode()); + if (override->mAlphaCutoff != LLGLTFMaterial::getDefaultAlphaCutoff()) mMaterialSummary.mAlphaCutoff = override->mAlphaCutoff; + } + + mInitialized = true; + } + + return true; + } + + bool mHasFacesWithoutPBR; + bool mHasFacesWithPBR; + bool mInitialized; + + LLGLTFMaterial* mMaterial; + LLGLTFMaterial mMaterialOverride; + LLGLTFMaterial mMaterialSummary; + + bool mIdenticalMaterial; + + bool mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT]; + bool mIdenticalBaseColor; + bool mIdenticalMetallic; + bool mIdenticalRoughness; + bool mIdenticalEmissive; + bool mIdenticalDoubleSided; + bool mIdenticalAlphaMode; + bool mIdenticalAlphaCutoff; + + LLUUID mMaterialId; +}; + +// +// "Use texture" label for normal/specular type comboboxes +// Filled in at initialization from translated strings +// +std::string USE_TEXTURE_LABEL; // subtly different (and more clear) name from llpanelface.cpp to avoid clashes -Zi + +FSPanelFace::FSPanelFace() : + LLPanel(), + mNeedMediaTitle(true), + mUnsavedChanges(0) +{ + // register callbacks before buildFromFile() or they won't work! + mCommitCallbackRegistrar.add("BuildTool.Flip", boost::bind(&FSPanelFace::onCommitFlip, this, _2)); + mCommitCallbackRegistrar.add("BuildTool.GLTFUVSpinner", boost::bind(&FSPanelFace::onCommitGLTFUVSpinner, this, _1, _2)); + mCommitCallbackRegistrar.add("BuildTool.SelectSameTexture", boost::bind(&FSPanelFace::onClickBtnSelectSameTexture, this, _1, _2)); + + buildFromFile("panel_fs_tools_texture.xml"); + + USE_TEXTURE_LABEL = LLTrans::getString("use_texture"); +} + +FSPanelFace::~FSPanelFace() +{ + unloadMedia(); +} + +// +// Methods +// + +// make sure all referenced UI controls are actually present in the skin +// and if not, terminate immediately with the line number of the error, +// so the skin creator will be alerted that something is wrong, and the +// rest of the code can assume all UI controls are actually there -Zi +#define SKIN_CHECK(x) if ( !(x) ) { skin_error(__LINE__); } + +void skin_error(int line) +{ + LL_ERRS("BuildTool") << "Skin error in line: " << line << LL_ENDL; +} + +void FSPanelFace::onMatTabChange() +{ + static S32 last_mat = -1; + if( auto curr_mat = getCurrentMaterialType(); curr_mat != last_mat ) + { + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + LLViewerObject* objectp = node ? node->getObject() : NULL; + if(objectp) + { + last_mat = curr_mat; + gSavedSettings.setBOOL("FSShowSelectedInBlinnPhong", (curr_mat == MATMEDIA_MATERIAL)); + objectp->markForUpdate(); + objectp->faceMappingChanged(); + } + } +} + +BOOL FSPanelFace::postBuild() +{ + // + // grab pointers to all relevant UI elements here and verify they are good + // + + // Tab controls + SKIN_CHECK(mTabsPBRMatMedia = findChild("tabs_material_type")); + SKIN_CHECK(mTabsMatChannel = findChild("tabs_blinn_phong_uvs")); + SKIN_CHECK(mTabsPBRChannel = findChild("tabs_pbr_transforms")); + + // common controls and parameters for Blinn-Phong and PBR + SKIN_CHECK(mBtnCopyFaces = findChild("copy_face_btn")); + SKIN_CHECK(mBtnPasteFaces = findChild("paste_face_btn")); + SKIN_CHECK(mCtrlGlow = findChild("glow")); + SKIN_CHECK(mCtrlRpt = findChild("rptctrl")); + + // Blinn-Phong alpha parameters + SKIN_CHECK(mCtrlColorTransp = findChild("ColorTrans")); + SKIN_CHECK(mColorTransPercent = findChild("color trans percent")); + SKIN_CHECK(mLabelAlphaMode = findChild("label alphamode")); + SKIN_CHECK(mComboAlphaMode = findChild("combobox alphamode")); + SKIN_CHECK(mCtrlMaskCutoff = findChild("maskcutoff")); + SKIN_CHECK(mCheckFullbright = findChild("checkbox fullbright")); + + // Blinn-Phong texture transforms and controls + SKIN_CHECK(mLabelTexGen = findChild("tex gen")); + SKIN_CHECK(mComboTexGen = findChild("combobox texgen")); + SKIN_CHECK(mCheckPlanarAlign = findChild("checkbox planar align")); + SKIN_CHECK(mLabelBumpiness = findChild("label bumpiness")); + SKIN_CHECK(mComboBumpiness = findChild("combobox bumpiness")); + SKIN_CHECK(mLabelShininess = findChild("label shininess")); + SKIN_CHECK(mComboShininess = findChild("combobox shininess")); + SKIN_CHECK(mCtrlTexScaleU = findChild("TexScaleU")); + SKIN_CHECK(mCtrlTexScaleV = findChild("TexScaleV")); + SKIN_CHECK(mCtrlTexOffsetU = findChild("TexOffsetU")); + SKIN_CHECK(mCtrlTexOffsetV = findChild("TexOffsetV")); + SKIN_CHECK(mCtrlTexRot = findChild("TexRot")); + SKIN_CHECK(mCtrlBumpyScaleU = findChild("bumpyScaleU")); + SKIN_CHECK(mCtrlBumpyScaleV = findChild("bumpyScaleV")); + SKIN_CHECK(mCtrlBumpyOffsetU = findChild("bumpyOffsetU")); + SKIN_CHECK(mCtrlBumpyOffsetV = findChild("bumpyOffsetV")); + SKIN_CHECK(mCtrlBumpyRot = findChild("bumpyRot")); + SKIN_CHECK(mCtrlShinyScaleU = findChild("shinyScaleU")); + SKIN_CHECK(mCtrlShinyScaleV = findChild("shinyScaleV")); + SKIN_CHECK(mCtrlShinyOffsetU = findChild("shinyOffsetU")); + SKIN_CHECK(mCtrlShinyOffsetV = findChild("shinyOffsetV")); + SKIN_CHECK(mCtrlShinyRot = findChild("shinyRot")); + SKIN_CHECK(mCtrlGlossiness = findChild("glossiness")); + SKIN_CHECK(mCtrlEnvironment = findChild("environment")); + + // Blinn-Phong Diffuse tint color swatch + SKIN_CHECK(mColorSwatch = findChild("colorswatch")); + + // Blinn-Phong Diffuse texture swatch + SKIN_CHECK(mTextureCtrl = findChild("texture control")); + + // Blinn-Phong Normal texture swatch + SKIN_CHECK(mBumpyTextureCtrl = findChild("bumpytexture control")); + + // Blinn-Phong Specular texture swatch + SKIN_CHECK(mShinyTextureCtrl = findChild("shinytexture control")); + + // Blinn-Phong Specular tint color swatch + SKIN_CHECK(mShinyColorSwatch = findChild("shinycolorswatch")); + + // Texture alignment and maps synchronization + SKIN_CHECK(mBtnAlignMedia = findChild("button align")); + SKIN_CHECK(mBtnAlignTextures = findChild("button align textures")); + SKIN_CHECK(mCheckSyncMaterials = findChild("checkbox_sync_settings")) + + // Media + SKIN_CHECK(mBtnDeleteMedia = findChild("delete_media")); + SKIN_CHECK(mBtnAddMedia = findChild("add_media")); + SKIN_CHECK(mTitleMedia = findChild("title_media")); + SKIN_CHECK(mTitleMediaText = findChild("media_info")); + + // PBR + SKIN_CHECK(mMaterialCtrlPBR = findChild("pbr_control")); + SKIN_CHECK(mBaseTexturePBR = findChild("base_color_picker")); + SKIN_CHECK(mBaseTintPBR = findChild("base_color_tint_picker")); + SKIN_CHECK(mNormalTexturePBR = findChild("normal_map_picker")); + SKIN_CHECK(mORMTexturePBR = findChild("metallic_map_picker")); + SKIN_CHECK(mEmissiveTexturePBR = findChild("emissive_map_picker")); + SKIN_CHECK(mEmissiveTintPBR = findChild("emissive_color_tint_picker")); + SKIN_CHECK(mCheckDoubleSidedPBR = findChild("double sided")); + SKIN_CHECK(mAlphaPBR = findChild("transparency")); + SKIN_CHECK(mLabelAlphaModePBR = findChild("blend mode label")); + SKIN_CHECK(mAlphaModePBR = findChild("alpha mode")); + SKIN_CHECK(mMaskCutoffPBR = findChild("alpha cutoff")); + SKIN_CHECK(mMetallicFactorPBR = findChild("metalness factor")); + SKIN_CHECK(mRoughnessFactorPBR = findChild("roughness factor")); + SKIN_CHECK(mBtnSavePBR = findChild("save_selected_pbr")); + + // + // hook up callbacks and do setup of all relevant UI elements here + // + mTabsPBRMatMedia->setCommitCallback(boost::bind(&FSPanelFace::onMatTabChange, this)); + // common controls and parameters for Blinn-Phong and PBR + mBtnCopyFaces->setCommitCallback(boost::bind(&FSPanelFace::onCopyFaces, this)); + mBtnPasteFaces->setCommitCallback(boost::bind(&FSPanelFace::onPasteFaces, this)); + mCtrlGlow->setCommitCallback(boost::bind(&FSPanelFace::onCommitGlow, this)); + mCtrlRpt->setCommitCallback(boost::bind(&FSPanelFace::onCommitRepeatsPerMeter, this)); + + // Blinn-Phong alpha parameters + mCtrlColorTransp->setCommitCallback(boost::bind(&FSPanelFace::onCommitAlpha, this)); + mComboAlphaMode->setCommitCallback(boost::bind(&FSPanelFace::onCommitAlphaMode, this)); + mCtrlMaskCutoff->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialMaskCutoff, this)); + mCheckFullbright->setCommitCallback(boost::bind(&FSPanelFace::onCommitFullbright, this)); + + // Blinn-Phong texture transforms and controls + mComboTexGen->setCommitCallback(boost::bind(&FSPanelFace::onCommitTexGen, this)); + mCheckPlanarAlign->setCommitCallback(boost::bind(&FSPanelFace::onCommitPlanarAlign, this)); + mComboBumpiness->setCommitCallback(boost::bind(&FSPanelFace::onCommitBump, this)); + mComboShininess->setCommitCallback(boost::bind(&FSPanelFace::onCommitShiny, this)); + mCtrlTexScaleU->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureScaleX, this)); + mCtrlTexScaleV->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureScaleY, this)); + mCtrlTexOffsetU->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureOffsetX, this)); + mCtrlTexOffsetV->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureOffsetY, this)); + mCtrlTexRot->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureRot, this)); + mCtrlBumpyScaleU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyScaleX, this)); + mCtrlBumpyScaleV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyScaleY, this)); + mCtrlBumpyOffsetU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyOffsetX, this)); + mCtrlBumpyOffsetV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyOffsetY, this)); + mCtrlBumpyRot->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyRot, this)); + mCtrlShinyScaleU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyScaleX, this)); + mCtrlShinyScaleV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyScaleY, this)); + mCtrlShinyOffsetU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyOffsetX, this)); + mCtrlShinyOffsetV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyOffsetY, this)); + mCtrlShinyRot->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyRot, this)); + mCtrlGlossiness->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialGloss, this)); + mCtrlEnvironment->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialEnv, this)); + + // Blinn-Phong Diffuse tint color swatch + mColorSwatch->setCommitCallback(boost::bind(&FSPanelFace::onCommitColor, this)); + mColorSwatch->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelColor, this)); + mColorSwatch->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectColor, this)); + + // Blinn-Phong Diffuse texture swatch + mTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_TEXTURE); + mTextureCtrl->setCommitCallback(boost::bind(&FSPanelFace::onCommitTexture, this, _1, _2)); + mTextureCtrl->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelTexture, this)); + mTextureCtrl->setDragCallback(boost::bind(&FSPanelFace::onDragTexture, this, _2)); + mTextureCtrl->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2)); + mTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); + + // Blinn-Phong Normal texture swatch + mBumpyTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_NORMAL); + mBumpyTextureCtrl->setBlankImageAssetID(BLANK_OBJECT_NORMAL); + mBumpyTextureCtrl->setCommitCallback(boost::bind(&FSPanelFace::onCommitNormalTexture, this, _1, _2)); + mBumpyTextureCtrl->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelNormalTexture, this)); + mBumpyTextureCtrl->setDragCallback(boost::bind(&FSPanelFace::onDragTexture, this, _2)); + mBumpyTextureCtrl->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2)); + mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mBumpyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); + + // Blinn-Phong Specular texture swatch + mShinyTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_SPECULAR); + mShinyTextureCtrl->setCommitCallback(boost::bind(&FSPanelFace::onCommitSpecularTexture, this, _1, _2)); + mShinyTextureCtrl->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelSpecularTexture, this)); + mShinyTextureCtrl->setDragCallback(boost::bind(&FSPanelFace::onDragTexture, this, _2)); + mShinyTextureCtrl->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2)); + mShinyTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mShinyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); + + // Blinn-Phong Specular tint color swatch + mShinyColorSwatch->setCommitCallback(boost::bind(&FSPanelFace::onCommitShinyColor, this)); + mShinyColorSwatch->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelShinyColor, this)); + mShinyColorSwatch->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectShinyColor, this)); + mShinyColorSwatch->setCanApplyImmediately(TRUE); + + // Texture alignment and maps synchronization + mBtnAlignMedia->setCommitCallback(boost::bind(&FSPanelFace::onClickAutoFix, this)); + mBtnAlignTextures->setCommitCallback(boost::bind(&FSPanelFace::onAlignTexture, this)); + mCheckSyncMaterials->setCommitCallback(boost::bind(&FSPanelFace::onClickMapsSync, this)); + + // Media + mBtnDeleteMedia->setCommitCallback(boost::bind(&FSPanelFace::onClickBtnDeleteMedia, this)); + mBtnAddMedia->setCommitCallback(boost::bind(&FSPanelFace::onClickBtnAddMedia, this)); + + // PBR Base Material swatch + // mMaterialCtrlPBR->setDefaultImageAssetID(LLUUID::null); // we have no default material, and null is standard for LLUUID -Zi + mMaterialCtrlPBR->setBlankImageAssetID(LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID); + mMaterialCtrlPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this)); + mMaterialCtrlPBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this)); + mMaterialCtrlPBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this)); + mMaterialCtrlPBR->setDragCallback(boost::bind(&FSPanelFace::onDragPbr, this, _2)); + mMaterialCtrlPBR->setOnTextureSelectedCallback(boost::bind(&FSPanelFace::onPbrSelectionChanged, this, _1)); + mMaterialCtrlPBR->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2)); + mMaterialCtrlPBR->setImmediateFilterPermMask(PERM_NONE); + mMaterialCtrlPBR->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); + mMaterialCtrlPBR->setBakeTextureEnabled(false); + mMaterialCtrlPBR->setInventoryPickType(PICK_MATERIAL); + + // PBR Base Color texture swatch + mBaseTexturePBR->setDefaultImageAssetID(DEFAULT_OBJECT_TEXTURE); + mBaseTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mBaseTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mBaseTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR Base Color tint color swatch + mBaseTintPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mBaseTintPBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mBaseTintPBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR Base Normal map swatch + mNormalTexturePBR->setDefaultImageAssetID(DEFAULT_OBJECT_NORMAL); + mNormalTexturePBR->setBlankImageAssetID(BLANK_OBJECT_NORMAL); + mNormalTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mNormalTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mNormalTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR Base Emissive map swatch + mEmissiveTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mEmissiveTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mEmissiveTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR Emissive tint color swatch + mEmissiveTintPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mEmissiveTintPBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mEmissiveTintPBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR Base (O)RM map swatch + mORMTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mORMTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mORMTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR parameters + mCheckDoubleSidedPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mAlphaPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mAlphaModePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mMaskCutoffPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mMetallicFactorPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mRoughnessFactorPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + + // PBR Save material button + mBtnSavePBR->setCommitCallback(boost::bind(&FSPanelFace::onClickBtnSavePBR, this)); + + // Only allow fully permissive textures + if (!gAgent.isGodlike()) + { + mBaseTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); + mNormalTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); + mORMTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); + mEmissiveTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); + } + + // + // set up user interface + // + + LLGLTFMaterialList::addSelectionUpdateCallback(onMaterialOverrideReceived); + sMaterialOverrideSelection.connect(); + + changePrecision(gSavedSettings.getS32("FSBuildToolDecimalPrecision")); + + selectMaterialType(MATMEDIA_PBR); // TODO: add tab switching signal + selectMatChannel(MATTYPE_DIFFUSE); // TODO: add tab switching signal + selectPBRChannel(PBRTYPE_RENDER_MATERIAL_ID); // TODO: add tab switching signal + + return TRUE; +} + +// +// Things the UI provides... +// + +LLUUID FSPanelFace::getCurrentNormalMap() { return mBumpyTextureCtrl->getImageAssetID(); } +LLUUID FSPanelFace::getCurrentSpecularMap() { return mShinyTextureCtrl->getImageAssetID(); } +U32 FSPanelFace::getCurrentShininess() { return mComboShininess->getCurrentIndex(); } +U32 FSPanelFace::getCurrentBumpiness() { return mComboBumpiness->getCurrentIndex(); } +U8 FSPanelFace::getCurrentDiffuseAlphaMode() { return (U8)mComboAlphaMode->getCurrentIndex(); } +U8 FSPanelFace::getCurrentAlphaMaskCutoff() { return (U8)mCtrlMaskCutoff->getValue().asInteger(); } +U8 FSPanelFace::getCurrentEnvIntensity() { return (U8)mCtrlEnvironment->getValue().asInteger(); } +U8 FSPanelFace::getCurrentGlossiness() { return (U8)mCtrlGlossiness->getValue().asInteger(); } +F32 FSPanelFace::getCurrentBumpyRot() { return mCtrlBumpyRot->getValue().asReal(); } +F32 FSPanelFace::getCurrentBumpyScaleU() { return mCtrlBumpyScaleU->getValue().asReal(); } +F32 FSPanelFace::getCurrentBumpyScaleV() { return mCtrlBumpyScaleV->getValue().asReal(); } +F32 FSPanelFace::getCurrentBumpyOffsetU() { return mCtrlBumpyOffsetU->getValue().asReal(); } +F32 FSPanelFace::getCurrentBumpyOffsetV() { return mCtrlBumpyOffsetV->getValue().asReal(); } +F32 FSPanelFace::getCurrentShinyRot() { return mCtrlShinyRot->getValue().asReal(); } +F32 FSPanelFace::getCurrentShinyScaleU() { return mCtrlShinyScaleU->getValue().asReal(); } +F32 FSPanelFace::getCurrentShinyScaleV() { return mCtrlShinyScaleV->getValue().asReal(); } +F32 FSPanelFace::getCurrentShinyOffsetU() { return mCtrlShinyOffsetU->getValue().asReal(); } +F32 FSPanelFace::getCurrentShinyOffsetV() { return mCtrlShinyOffsetV->getValue().asReal(); } + +// UI provided diffuse parameters +F32 FSPanelFace::getCurrentTextureRot() { return mCtrlTexRot->getValue().asReal(); } +F32 FSPanelFace::getCurrentTextureScaleU() { return mCtrlTexScaleU->getValue().asReal(); } +F32 FSPanelFace::getCurrentTextureScaleV() { return mCtrlTexScaleV->getValue().asReal(); } +F32 FSPanelFace::getCurrentTextureOffsetU() { return mCtrlTexOffsetU->getValue().asReal(); } +F32 FSPanelFace::getCurrentTextureOffsetV() { return mCtrlTexOffsetV->getValue().asReal(); } +// + +LLRender::eTexIndex FSPanelFace::getTextureChannelToEdit() +{ + LLRender::eTexIndex channel_to_edit = LLRender::DIFFUSE_MAP; + + S32 matmedia_selection = getCurrentMaterialType(); + + if (matmedia_selection == MATMEDIA_MATERIAL) + { + channel_to_edit = (LLRender::eTexIndex) getCurrentMatChannel(); + + if (channel_to_edit == LLRender::NORMAL_MAP && getCurrentNormalMap().isNull()) return LLRender::DIFFUSE_MAP; + if (channel_to_edit == LLRender::SPECULAR_MAP && getCurrentSpecularMap().isNull()) return LLRender::DIFFUSE_MAP; + } + + // this is technically not correct, the return type is not the same, which forces us to cast -Zi + else if (matmedia_selection == MATMEDIA_PBR) + { + channel_to_edit = (LLRender::eTexIndex) getCurrentPBRChannel(); + + if (channel_to_edit == PBRTYPE_NORMAL && mNormalTexturePBR->getImageAssetID().isNull()) return (LLRender::eTexIndex) PBRTYPE_BASE_COLOR; + if (channel_to_edit == PBRTYPE_METALLIC_ROUGHNESS && mORMTexturePBR->getImageAssetID().isNull()) return (LLRender::eTexIndex) PBRTYPE_BASE_COLOR; + if (channel_to_edit == PBRTYPE_EMISSIVE && mEmissiveTexturePBR->getImageAssetID().isNull()) return (LLRender::eTexIndex) PBRTYPE_BASE_COLOR; + } + + return channel_to_edit; +} + +LLRender::eTexIndex FSPanelFace::getTextureDropChannel() +{ + if (getCurrentMaterialType() == MATMEDIA_MATERIAL) + { + return getTextureChannelToEdit(); + } + + return LLRender::eTexIndex(MATTYPE_DIFFUSE); +} + +LLGLTFMaterial::TextureInfo FSPanelFace::getPBRDropChannel() +{ + if (getCurrentMaterialType() == MATMEDIA_PBR) + { + S32 current_pbr_channel = getCurrentPBRChannel(); + if (current_pbr_channel == PBRTYPE_NORMAL) return LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL; + if (current_pbr_channel == PBRTYPE_METALLIC_ROUGHNESS) return LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS; + if (current_pbr_channel == PBRTYPE_EMISSIVE) return LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE; + } + return LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR; +} + +LLMaterialPtr FSPanelFace::createDefaultMaterial(LLMaterialPtr current_material) +{ + LLMaterialPtr new_material(current_material.notNull() ? new LLMaterial(current_material->asLLSD()) : new LLMaterial()); + llassert_always(new_material); + + // Preserve old diffuse alpha mode or assert correct default blend mode as appropriate for the alpha channel content of the diffuse texture + // + new_material->setDiffuseAlphaMode(current_material.isNull() ? (isAlpha() ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE) : current_material->getDiffuseAlphaMode()); + return new_material; +} + +void FSPanelFace::onVisibilityChange(BOOL new_visibility) +{ + if (new_visibility) + { + gAgent.showLatestFeatureNotification("gltf"); + } + LLPanel::onVisibilityChange(new_visibility); +} + +void FSPanelFace::draw() +{ + // TODO(Beq) why does it have to call applyTE? + updateCopyTexButton(); + + // grab media name/title and update the UI widget + // Todo: move it, it's preferable not to update + // labels inside draw + updateMediaTitle(); + + LLPanel::draw(); + + // not sure if there isn't a better place for this, but for the time being this seems to work, + // and trying other places always failed in some way or other -Zi + static U64MicrosecondsImplicit next_update_time = 0LL; + if (mUnsavedChanges && gFrameTime > next_update_time) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "detected unsaved changes: " << mUnsavedChanges << LL_ENDL; + + LLPointer mat = new LLGLTFMaterial(); + getGLTFMaterial(mat); + + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + LLRenderMaterialOverrideFunctor override_func(mat, mUnsavedChanges); + selected_objects->applyToNodes(&override_func); + + LLGLTFMaterialList::flushUpdates(); + + mUnsavedChanges = 0; + + next_update_time = gFrameTime + 100000LL; // 100 ms + + // delete mat; // do not delete mat, it's still referenced elsewhere (probably in the material list) -Zi + } + + if (sMaterialOverrideSelection.update()) + { + setMaterialOverridesFromSelection(); + updatePBROverrideDisplay(); + } +} + +void FSPanelFace::sendTexture() +{ + if (!mTextureCtrl->getTentative()) + { + // we grab the item id first, because we want to do a + // permissions check in the selection manager. ARGH! + LLUUID id = mTextureCtrl->getImageItemID(); + if (id.isNull()) + { + id = mTextureCtrl->getImageAssetID(); + } + if (!LLSelectMgr::getInstance()->selectionSetImage(id, getCurrentMaterialType()==MATMEDIA_PBR) ) + { + // need to refresh value in texture ctrl + refresh(); + } + } +} + +void FSPanelFace::sendBump(U32 bumpiness) +{ + if (bumpiness < BUMPY_TEXTURE) + { + LL_DEBUGS("Materials") << "clearing bumptexture control" << LL_ENDL; + mBumpyTextureCtrl->clear(); + mBumpyTextureCtrl->setImageAssetID(LLUUID()); + } + + updateBumpyControls(bumpiness == BUMPY_TEXTURE, true); + + LLUUID current_normal_map = mBumpyTextureCtrl->getImageAssetID(); + + U8 bump = (U8)bumpiness & TEM_BUMP_MASK; + + // Clear legacy bump to None when using an actual normal map + // + if (!current_normal_map.isNull()) + { + bump = 0; + } + + // Set the normal map or reset it to null as appropriate + // + LLSelectedTEMaterial::setNormalID(this, current_normal_map); + LLSelectMgr::getInstance()->selectionSetBumpmap(bump, mBumpyTextureCtrl->getImageItemID()); +} + +void FSPanelFace::sendTexGen() +{ + U8 tex_gen = (U8) mComboTexGen->getCurrentIndex() << TEM_TEX_GEN_SHIFT; + LLSelectMgr::getInstance()->selectionSetTexGen(tex_gen); +} + +void FSPanelFace::sendShiny(U32 shininess) +{ + if (shininess < SHINY_TEXTURE) + { + mShinyTextureCtrl->clear(); + mShinyTextureCtrl->setImageAssetID(LLUUID()); + } + + LLUUID specmap = getCurrentSpecularMap(); + + U8 shiny = (U8)shininess & TEM_SHINY_MASK; + if (!specmap.isNull()) + { + shiny = 0; + } + + LLSelectedTEMaterial::setSpecularID(this, specmap); + LLSelectMgr::getInstance()->selectionSetShiny(shiny, mShinyTextureCtrl->getImageItemID()); + + updateShinyControls(!specmap.isNull(), true); +} + +void FSPanelFace::sendFullbright() +{ + U8 fullbright = mCheckFullbright->get() ? TEM_FULLBRIGHT_MASK : 0; + LLSelectMgr::getInstance()->selectionSetFullbright(fullbright); +} + +void FSPanelFace::sendColor() +{ + LLSelectMgr::getInstance()->selectionSetColorOnly(mColorSwatch->get()); +} + +void FSPanelFace::sendAlpha() +{ + F32 alpha = (100.0f - mCtrlColorTransp->get()) / 100.0f; + LLSelectMgr::getInstance()->selectionSetAlphaOnly(alpha); +} + +void FSPanelFace::sendGlow() +{ + LLSelectMgr::getInstance()->selectionSetGlow(mCtrlGlow->get()); +} + +struct FSPanelFaceSetTEFunctor : public LLSelectedTEFunctor +{ + FSPanelFaceSetTEFunctor(FSPanelFace* panel) : + mPanel(panel) + { + } + + virtual bool apply(LLViewerObject* object, S32 te) + { + BOOL valid; + F32 value; + std::string prefix; + + // Effectively the same as MATMEDIA_PBR - separate for the sake of clarity + + const std::string& tab_name = mPanel->mTabsMatChannel->getCurrentPanel()->getName(); + + prefix = "Tex"; + if (tab_name == "panel_blinn_phong_normal") + { + prefix = "bumpy"; + } + else if (tab_name == "panel_blinn_phong_specular") + { + prefix = "shiny"; + } + + LLSpinCtrl* ctrlTexScaleS = mPanel->findChild(prefix + "ScaleU"); + LLSpinCtrl* ctrlTexScaleT = mPanel->findChild(prefix + "ScaleV"); + LLSpinCtrl* ctrlTexOffsetS = mPanel->findChild(prefix + "OffsetU"); + LLSpinCtrl* ctrlTexOffsetT = mPanel->findChild(prefix + "OffsetV"); + LLSpinCtrl* ctrlTexRotation = mPanel->findChild(prefix + "Rot"); + + bool align_planar = mPanel->mCheckPlanarAlign->get(); + + llassert(comboTexGen); + llassert(object); + + if (ctrlTexScaleS) + { + valid = !ctrlTexScaleS->getTentative(); + if (valid || align_planar) + { + value = ctrlTexScaleS->get(); + if (mPanel->mComboTexGen->getCurrentIndex() == 1) + { + value *= 0.5f; + } + object->setTEScaleS(te, value); + + if (align_planar) + { + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, value, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, value, te, object->getID()); + } + } + } + + if (ctrlTexScaleT) + { + valid = !ctrlTexScaleT->getTentative(); + if (valid || align_planar) + { + value = ctrlTexScaleT->get(); + if (mPanel->mComboTexGen->getCurrentIndex() == 1) + { + value *= 0.5f; + } + object->setTEScaleT(te, value); + + if (align_planar) + { + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, value, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, value, te, object->getID()); + } + } + } + + if (ctrlTexOffsetS) + { + valid = !ctrlTexOffsetS->getTentative(); + if (valid || align_planar) + { + value = ctrlTexOffsetS->get(); + object->setTEOffsetS(te, value); + + if (align_planar) + { + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, value, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetX(mPanel, value, te, object->getID()); + } + } + } + + if (ctrlTexOffsetT) + { + valid = !ctrlTexOffsetT->getTentative(); + if (valid || align_planar) + { + value = ctrlTexOffsetT->get(); + object->setTEOffsetT(te, value); + + if (align_planar) + { + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, value, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetY(mPanel, value, te, object->getID()); + } + } + } + + if (ctrlTexRotation) + { + valid = !ctrlTexRotation->getTentative(); + if (valid || align_planar) + { + value = ctrlTexRotation->get() * DEG_TO_RAD; + object->setTERotation(te, value); + + if (align_planar) + { + FSPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, value, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, value, te, object->getID()); + } + } + } + return true; + } +private: + FSPanelFace* mPanel; +}; + +// Functor that aligns a face to mCenterFace +struct FSPanelFaceSetAlignedTEFunctor : public LLSelectedTEFunctor +{ + FSPanelFaceSetAlignedTEFunctor(FSPanelFace* panel, LLFace* center_face) : + mPanel(panel), + mCenterFace(center_face) + { + } + + virtual bool apply(LLViewerObject* object, S32 te) + { + LLFace* facep = object->mDrawable->getFace(te); + if (!facep) + { + return true; + } + + if (facep->getViewerObject()->getVolume()->getNumVolumeFaces() <= te) + { + return true; + } + + bool set_aligned = true; + if (facep == mCenterFace) + { + set_aligned = false; + } + if (set_aligned) + { + LLVector2 uv_offset, uv_scale; + F32 uv_rot; + set_aligned = facep->calcAlignedPlanarTE(mCenterFace, &uv_offset, &uv_scale, &uv_rot); + if (set_aligned) + { + object->setTEOffset(te, uv_offset.mV[VX], uv_offset.mV[VY]); + object->setTEScale(te, uv_scale.mV[VX], uv_scale.mV[VY]); + object->setTERotation(te, uv_rot); + + FSPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, uv_rot, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, uv_rot, te, object->getID()); + + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, uv_offset.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, uv_offset.mV[VY], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, uv_scale.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, uv_scale.mV[VY], te, object->getID()); + + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetX(mPanel, uv_offset.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetY(mPanel, uv_offset.mV[VY], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, uv_scale.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, uv_scale.mV[VY], te, object->getID()); + } + } + if (!set_aligned) + { + FSPanelFaceSetTEFunctor setfunc(mPanel); + setfunc.apply(object, te); + } + return true; + } +private: + FSPanelFace* mPanel; + LLFace* mCenterFace; +}; + +struct FSPanelFaceSetAlignedConcreteTEFunctor : public LLSelectedTEFunctor +{ + FSPanelFaceSetAlignedConcreteTEFunctor(FSPanelFace* panel, LLFace* center_face, LLRender::eTexIndex map) : + mPanel(panel), + mChefFace(center_face), + mMap(map) + { + } + + virtual bool apply(LLViewerObject* object, S32 te) + { + LLFace* facep = object->mDrawable->getFace(te); + if (!facep) + { + return true; + } + + if (facep->getViewerObject()->getVolume()->getNumVolumeFaces() <= te) + { + return true; + } + + if (mChefFace != facep) + { + LLVector2 uv_offset, uv_scale; + F32 uv_rot; + if (facep->calcAlignedPlanarTE(mChefFace, &uv_offset, &uv_scale, &uv_rot, mMap)) + { + switch (mMap) + { + case LLRender::DIFFUSE_MAP: + object->setTEOffset(te, uv_offset.mV[VX], uv_offset.mV[VY]); + object->setTEScale(te, uv_scale.mV[VX], uv_scale.mV[VY]); + object->setTERotation(te, uv_rot); + break; + + case LLRender::NORMAL_MAP: + FSPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, uv_rot, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, uv_offset.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, uv_offset.mV[VY], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, uv_scale.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, uv_scale.mV[VY], te, object->getID()); + break; + + case LLRender::SPECULAR_MAP: + FSPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, uv_rot, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetX(mPanel, uv_offset.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetY(mPanel, uv_offset.mV[VY], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, uv_scale.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, uv_scale.mV[VY], te, object->getID()); + break; + + default: /*make compiler happy*/ + break; + } + } + } + + return true; + } + + private: + FSPanelFace* mPanel; + LLFace* mChefFace; + LLRender::eTexIndex mMap; +}; + +// Functor that tests if a face is aligned to mCenterFace +struct FSPanelFaceGetIsAlignedTEFunctor : public LLSelectedTEFunctor +{ + FSPanelFaceGetIsAlignedTEFunctor(LLFace* center_face) : + mCenterFace(center_face) + { + } + + virtual bool apply(LLViewerObject* object, S32 te) + { + LLFace* facep = object->mDrawable->getFace(te); + if (!facep) + { + return false; + } + + if (facep->getViewerObject()->getVolume()->getNumVolumeFaces() <= te) + { //volume face does not exist, can't be aligned + return false; + } + + if (facep == mCenterFace) + { + return true; + } + + LLVector2 aligned_st_offset, aligned_st_scale; + F32 aligned_st_rot; + if ( facep->calcAlignedPlanarTE(mCenterFace, &aligned_st_offset, &aligned_st_scale, &aligned_st_rot) ) + { + const LLTextureEntry* tep = facep->getTextureEntry(); + LLVector2 st_offset, st_scale; + tep->getOffset(&st_offset.mV[VX], &st_offset.mV[VY]); + tep->getScale(&st_scale.mV[VX], &st_scale.mV[VY]); + F32 st_rot = tep->getRotation(); + + bool eq_offset_x = is_approx_equal_fraction(st_offset.mV[VX], aligned_st_offset.mV[VX], 12); + bool eq_offset_y = is_approx_equal_fraction(st_offset.mV[VY], aligned_st_offset.mV[VY], 12); + bool eq_scale_x = is_approx_equal_fraction(st_scale.mV[VX], aligned_st_scale.mV[VX], 12); + bool eq_scale_y = is_approx_equal_fraction(st_scale.mV[VY], aligned_st_scale.mV[VY], 12); + bool eq_rot = is_approx_equal_fraction(st_rot, aligned_st_rot, 6); + + // needs a fuzzy comparison, because of fp errors + if (eq_offset_x && + eq_offset_y && + eq_scale_x && + eq_scale_y && + eq_rot) + { + return true; + } + } + return false; + } + private: + LLFace* mCenterFace; +}; + +struct FSPanelFaceSendFunctor : public LLSelectedObjectFunctor +{ + virtual bool apply(LLViewerObject* object) + { + object->sendTEUpdate(); + return true; + } +}; + +void FSPanelFace::sendTextureInfo() +{ + if (mCheckPlanarAlign->getValue().asBoolean()) + { + LLFace* last_face = NULL; + bool identical_face =false; + LLSelectedTE::getFace(last_face, identical_face); + FSPanelFaceSetAlignedTEFunctor setfunc(this, last_face); + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); + } + else + { + FSPanelFaceSetTEFunctor setfunc(this); + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); + } + + FSPanelFaceSendFunctor sendfunc; + LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc); +} + +void FSPanelFace::alignTextureLayer() +{ + LLFace* last_face = NULL; + bool identical_face = false; + LLSelectedTE::getFace(last_face, identical_face); + + // TODO: make this respect PBR channels -Zi + FSPanelFaceSetAlignedConcreteTEFunctor setfunc(this, last_face, getTextureChannelToEdit()); + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); +} + +void FSPanelFace::getState() +{ + updateUI(); +} + +void FSPanelFace::updateUI(bool force_set_values /*false*/) +{ //set state of UI to match state of texture entry(ies) (calls setEnabled, setValue, etc, but NOT setVisible) + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + LLViewerObject* objectp = node ? node->getObject() : NULL; + + if (objectp + && objectp->getPCode() == LL_PCODE_VOLUME + && objectp->permModify()) + { + // TODO: Find out what "permanent" objects are supposed to allow to be edited. Right now this will + // completely blank out the texture panel, so we could just move that into the if() above -Zi + bool editable = !objectp->isPermanentEnforced(); + bool attachment = objectp->isAttachment(); + + // this object's faces can potentially be edited by us, so display the edit controls unless this is + // a "permanent" pathfinding(?) object -Zi + gSavedSettings.setBOOL("FSInternalCanEditObjectFaces", editable); + LL_DEBUGS("ENABLEDISABLETOOLS") << "show face edit controls: " << editable << LL_ENDL; + + // TODO: editable always true here so we don't have to go through all the following code and strip it out + // until we know what the permanent thing abobe is supposed to do and we know if blanking out all + // controls has any unforseen side effects to editing. -Zi + editable = true; + + bool has_pbr_material; + bool has_faces_without_pbr; + updateUIGLTF(objectp, has_pbr_material, has_faces_without_pbr, force_set_values); + + // TODO: if has_pbr_material AND has_faces_without_pbr give "Mixed Selection!" warning somehow + + mTabsPBRMatMedia->enableTabButton( + mTabsPBRMatMedia->getIndexForPanel( + mTabsPBRMatMedia->getPanelByName("panel_material_type_blinn_phong")), editable ); + + // only turn on auto-adjust button if there is a media renderer and the media is loaded + mBtnAlignMedia->setEnabled(editable); + + bool enable_material_controls = (!gSavedSettings.getBOOL("SyncMaterialSettings")); + + // *NOTE: The "identical" variable is currently only used to decide if + // the texgen control should be tentative - this is not used by GLTF + // materials. -Cosmic;2022-11-09 + bool identical = true; // true because it is anded below + bool identical_diffuse = false; + bool identical_norm = false; + bool identical_spec = false; + + LLUUID id; + LLUUID normmap_id; + LLUUID specmap_id; + + LLSelectedTE::getTexId(id, identical_diffuse); + LLSelectedTEMaterial::getNormalID(normmap_id, identical_norm); + LLSelectedTEMaterial::getSpecularID(specmap_id, identical_spec); + + mTabsMatChannel->setEnabled(editable); + mTabsPBRChannel->setEnabled(editable); + + mCheckSyncMaterials->setEnabled(editable); + mCheckSyncMaterials->setValue(gSavedSettings.getBOOL("SyncMaterialSettings")); + + updateVisibility(objectp); + + LLColor4 color = LLColor4::white; + bool identical_color = false; + + LLSelectedTE::getColor(color, identical_color); + LLColor4 prev_color = mColorSwatch->get(); + + mColorSwatch->setOriginal(color); + mColorSwatch->set(color, force_set_values || (prev_color != color) || !editable); + + mColorSwatch->setValid(editable); + mColorSwatch->setEnabled(editable); + mColorSwatch->setCanApplyImmediately( editable ); + + F32 transparency = (1.f - color.mV[VALPHA]) * 100.f; + mCtrlColorTransp->setValue(editable ? transparency : 0); + mCtrlColorTransp->setEnabled(editable ); + mColorTransPercent->setMouseOpaque(editable ); + + U8 shiny = 0; + // Shiny + { + bool identical_shiny = false; + + // Shiny - Legacy only, Blinn-Pbong specular is done further down + LLSelectedTE::getShiny(shiny, identical_shiny); + identical = identical && identical_shiny; + + shiny = specmap_id.isNull() ? shiny : SHINY_TEXTURE; + + mComboShininess->selectNthItem(shiny); + mComboShininess->setEnabled(editable); + mComboShininess->setTentative(!identical_shiny); + mLabelShininess->setEnabled(editable); + } + + U8 bumpy = 0; + // Bumpy + { + bool identical_bumpy = false; + LLSelectedTE::getBumpmap(bumpy, identical_bumpy); + + LLUUID norm_map_id = getCurrentNormalMap(); + + bumpy = norm_map_id.isNull() ? bumpy : BUMPY_TEXTURE; + + mComboBumpiness->selectNthItem(bumpy); + mComboBumpiness->setEnabled(editable); + mComboBumpiness->setTentative(!identical_bumpy); + mLabelBumpiness->setEnabled(editable); + } + + // Texture + { + mIsAlpha = false; + + LLGLenum image_format = GL_RGB; + bool identical_image_format = false; + LLSelectedTE::getImageFormat(image_format, identical_image_format); + + switch (image_format) + { + case GL_RGBA: + case GL_ALPHA: + { + mIsAlpha = true; + } + break; + + case GL_RGB: break; + default: + { + LL_WARNS() << "Unexpected tex format in FSPanelFace...resorting to no alpha" << LL_ENDL; + } + break; + } + + if (LLViewerMedia::getInstance()->textureHasMedia(id)) + { + mBtnAlignMedia->setEnabled(editable); + } + + if (identical_diffuse) + { + mTextureCtrl->setTentative(false); + mTextureCtrl->setEnabled(editable); + mTextureCtrl->setImageAssetID(id); + mComboAlphaMode->setEnabled(editable && mIsAlpha && transparency <= 0.f ); + mCtrlMaskCutoff->setEnabled(editable && mIsAlpha ); + + mTextureCtrl->setBakeTextureEnabled(true); + } + else if (id.isNull()) + { + // None selected + mTextureCtrl->setTentative(false); + mTextureCtrl->setEnabled(false); + mTextureCtrl->setImageAssetID(LLUUID::null); + mComboAlphaMode->setEnabled(false); + mCtrlMaskCutoff->setEnabled(false); + + mTextureCtrl->setBakeTextureEnabled(false); + } + else + { + // Tentative: multiple selected with different textures + mTextureCtrl->setTentative(true); + mTextureCtrl->setEnabled(editable ); + mTextureCtrl->setImageAssetID(id); + mComboAlphaMode->setEnabled(editable && mIsAlpha && transparency <= 0.f ); + mCtrlMaskCutoff->setEnabled(editable && mIsAlpha ); + + mTextureCtrl->setBakeTextureEnabled(true); + } + + mShinyTextureCtrl->setTentative(!identical_spec); + mShinyTextureCtrl->setEnabled(editable); + mShinyTextureCtrl->setImageAssetID(specmap_id); + + mBumpyTextureCtrl->setTentative(!identical_norm); + mBumpyTextureCtrl->setEnabled(editable ); + mBumpyTextureCtrl->setImageAssetID(normmap_id); + + if (attachment) + { + // attachments are in world and in inventory, + // server doesn't support changing permissions + // in such case + mTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + mShinyTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + } + else + { + mTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mShinyTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + } + + // Diffuse Alpha Mode + + // Init to the default that is appropriate for the alpha content of the asset + // + U8 alpha_mode = mIsAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + + bool identical_alpha_mode = false; + + // See if that's been overridden by a material setting for same... + // + LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode, mIsAlpha); + + // it is invalid to have any alpha mode other than blend if transparency is greater than zero ... + // Want masking? Want emissive? Tough! You get BLEND! + alpha_mode = (transparency > 0.f) ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : alpha_mode; + + // ... unless there is no alpha channel in the texture, in which case alpha mode MUST be none + alpha_mode = mIsAlpha ? alpha_mode : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + + mComboAlphaMode->selectNthItem(alpha_mode); + + updateAlphaControls(); + + mLabelAlphaMode->setEnabled(mComboAlphaMode->getEnabled()); + } + + // planar align + bool align_planar = mCheckPlanarAlign->get(); + bool identical_planar_aligned = false; + { + const bool texture_info_selected = (getCurrentMaterialType() == MATMEDIA_PBR && getCurrentPBRChannel() != PBRTYPE_RENDER_MATERIAL_ID); + const bool enabled = (editable && isIdenticalPlanarTexgen() && !texture_info_selected); + + mCheckPlanarAlign->setValue(align_planar && enabled); + mCheckPlanarAlign->setEnabled(enabled); + mBtnAlignTextures->setEnabled(enabled && LLSelectMgr::getInstance()->getSelection()->getObjectCount() > 1); + + if (align_planar && enabled) + { + LLFace* last_face = nullptr; + bool identical_face = false; + LLSelectedTE::getFace(last_face, identical_face); + + FSPanelFaceGetIsAlignedTEFunctor get_is_aligend_func(last_face); + // this will determine if the texture param controls are tentative: + identical_planar_aligned = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&get_is_aligend_func); + } + } + + // Needs to be public and before tex scale settings below to properly reflect + // behavior when in planar vs default texgen modes in the + // NORSPEC-84 et al + // + LLTextureEntry::e_texgen selected_texgen = LLTextureEntry::TEX_GEN_DEFAULT; + bool identical_texgen = true; + bool identical_planar_texgen = false; + + { + LLSelectedTE::getTexGen(selected_texgen, identical_texgen); + identical_planar_texgen = (identical_texgen && (selected_texgen == LLTextureEntry::TEX_GEN_PLANAR)); + } + + // Texture scale + { + bool identical_diff_scale_s = false; + bool identical_spec_scale_s = false; + bool identical_norm_scale_s = false; + + identical = align_planar ? identical_planar_aligned : identical; + + F32 diff_scale_s = 1.f; + F32 spec_scale_s = 1.f; + F32 norm_scale_s = 1.f; + + LLSelectedTE::getScaleS(diff_scale_s, identical_diff_scale_s); + LLSelectedTEMaterial::getSpecularRepeatX(spec_scale_s, identical_spec_scale_s); + LLSelectedTEMaterial::getNormalRepeatX(norm_scale_s, identical_norm_scale_s); + + diff_scale_s = editable ? diff_scale_s : 1.0f; + diff_scale_s *= identical_planar_texgen ? 2.0f : 1.0f; + + norm_scale_s = editable ? norm_scale_s : 1.0f; + norm_scale_s *= identical_planar_texgen ? 2.0f : 1.0f; + + spec_scale_s = editable ? spec_scale_s : 1.0f; + spec_scale_s *= identical_planar_texgen ? 2.0f : 1.0f; + + mCtrlTexScaleU->setValue(diff_scale_s); + mCtrlShinyScaleU->setValue(spec_scale_s); + mCtrlBumpyScaleU->setValue(norm_scale_s); + + // TODO: do we need to enable/disable all these manually anymore? -Zi + /* + mCtrlTexScaleU->setEnabled(editable && has_material); + + mCtrlShinyScaleU->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls); + mCtrlBumpyScaleU->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls); + childSetEnabled("flipTextureScaleSU", mCtrlShinyScaleU->getEnabled()); + childSetEnabled("flipTextureScaleNU", mCtrlBumpyScaleU->getEnabled()); + */ + + bool diff_scale_tentative = !(identical && identical_diff_scale_s); + bool norm_scale_tentative = !(identical && identical_norm_scale_s); + bool spec_scale_tentative = !(identical && identical_spec_scale_s); + + mCtrlTexScaleU->setTentative( LLSD(diff_scale_tentative)); + mCtrlShinyScaleU->setTentative(LLSD(spec_scale_tentative)); + mCtrlBumpyScaleU->setTentative(LLSD(norm_scale_tentative)); + + mCheckSyncMaterials->setEnabled(editable && (specmap_id.notNull() || normmap_id.notNull()) && !align_planar); + } + + { + bool identical_diff_scale_t = false; + bool identical_spec_scale_t = false; + bool identical_norm_scale_t = false; + + F32 diff_scale_t = 1.f; + F32 spec_scale_t = 1.f; + F32 norm_scale_t = 1.f; + + LLSelectedTE::getScaleT(diff_scale_t, identical_diff_scale_t); + LLSelectedTEMaterial::getSpecularRepeatY(spec_scale_t, identical_spec_scale_t); + LLSelectedTEMaterial::getNormalRepeatY(norm_scale_t, identical_norm_scale_t); + + diff_scale_t = editable ? diff_scale_t : 1.0f; + diff_scale_t *= identical_planar_texgen ? 2.0f : 1.0f; + + norm_scale_t = editable ? norm_scale_t : 1.0f; + norm_scale_t *= identical_planar_texgen ? 2.0f : 1.0f; + + spec_scale_t = editable ? spec_scale_t : 1.0f; + spec_scale_t *= identical_planar_texgen ? 2.0f : 1.0f; + + bool diff_scale_tentative = !identical_diff_scale_t; + bool norm_scale_tentative = !identical_norm_scale_t; + bool spec_scale_tentative = !identical_spec_scale_t; + + // TODO: do we need to enable/disable all these manually anymore? -Zi + /* + mCtrlTexScaleV->setEnabled(editable && has_material); + + mCtrlShinyScaleV->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls); + mCtrlBumpyScaleV->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls); + childSetEnabled("flipTextureScaleSV", mCtrlShinyScaleU->getEnabled()); + childSetEnabled("flipTextureScaleNV", mCtrlBumpyScaleU->getEnabled()); + */ + + if (force_set_values) + { + mCtrlTexScaleV->forceSetValue(diff_scale_t); + } + else + { + mCtrlTexScaleV->setValue(diff_scale_t); + } + mCtrlShinyScaleV->setValue(norm_scale_t); + mCtrlBumpyScaleV->setValue(spec_scale_t); + + mCtrlTexScaleV->setTentative(LLSD(diff_scale_tentative)); + mCtrlShinyScaleV->setTentative(LLSD(norm_scale_tentative)); + mCtrlBumpyScaleV->setTentative(LLSD(spec_scale_tentative)); + } + + // Texture offset + { + bool identical_diff_offset_s = false; + bool identical_norm_offset_s = false; + bool identical_spec_offset_s = false; + + F32 diff_offset_s = 0.0f; + F32 norm_offset_s = 0.0f; + F32 spec_offset_s = 0.0f; + + LLSelectedTE::getOffsetS(diff_offset_s, identical_diff_offset_s); + LLSelectedTEMaterial::getNormalOffsetX(norm_offset_s, identical_norm_offset_s); + LLSelectedTEMaterial::getSpecularOffsetX(spec_offset_s, identical_spec_offset_s); + + bool diff_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_diff_offset_s); + bool norm_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_norm_offset_s); + bool spec_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_spec_offset_s); + + mCtrlTexOffsetU->setValue( editable ? diff_offset_s : 0.0f); + mCtrlBumpyOffsetU->setValue(editable ? norm_offset_s : 0.0f); + mCtrlShinyOffsetU->setValue(editable ? spec_offset_s : 0.0f); + + mCtrlTexOffsetU->setTentative(LLSD(diff_offset_u_tentative)); + mCtrlBumpyOffsetU->setTentative(LLSD(norm_offset_u_tentative)); + mCtrlShinyOffsetU->setTentative(LLSD(spec_offset_u_tentative)); + + // TODO: do we need to enable/disable all these manually anymore? -Zi + /* + mCtrlTexOffsetU->setEnabled(editable && has_material); + + mCtrlShinyOffsetU->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls); + mCtrlBumpyOffsetU->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls); + */ + } + + { + bool identical_diff_offset_t = false; + bool identical_norm_offset_t = false; + bool identical_spec_offset_t = false; + + F32 diff_offset_t = 0.0f; + F32 norm_offset_t = 0.0f; + F32 spec_offset_t = 0.0f; + + LLSelectedTE::getOffsetT(diff_offset_t, identical_diff_offset_t); + LLSelectedTEMaterial::getNormalOffsetY(norm_offset_t, identical_norm_offset_t); + LLSelectedTEMaterial::getSpecularOffsetY(spec_offset_t, identical_spec_offset_t); + + bool diff_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_diff_offset_t); + bool norm_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_norm_offset_t); + bool spec_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_spec_offset_t); + + mCtrlTexOffsetV->setValue( editable ? diff_offset_t : 0.0f); + mCtrlBumpyOffsetV->setValue(editable ? norm_offset_t : 0.0f); + mCtrlShinyOffsetV->setValue(editable ? spec_offset_t : 0.0f); + + mCtrlTexOffsetV->setTentative(LLSD(diff_offset_v_tentative)); + mCtrlBumpyOffsetV->setTentative(LLSD(norm_offset_v_tentative)); + mCtrlShinyOffsetV->setTentative(LLSD(spec_offset_v_tentative)); + + // TODO: do we need to enable/disable all these manually anymore? -Zi + /* + mCtrlTexOffsetV->setEnabled(editable && has_material); + + mCtrlShinyOffsetV->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls); + mCtrlBumpyOffsetV->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls); + */ + } + + // Texture rotation + { + bool identical_diff_rotation = false; + bool identical_norm_rotation = false; + bool identical_spec_rotation = false; + + F32 diff_rotation = 0.f; + F32 norm_rotation = 0.f; + F32 spec_rotation = 0.f; + + LLSelectedTE::getRotation(diff_rotation,identical_diff_rotation); + LLSelectedTEMaterial::getSpecularRotation(spec_rotation,identical_spec_rotation); + LLSelectedTEMaterial::getNormalRotation(norm_rotation,identical_norm_rotation); + + bool diff_rot_tentative = !(align_planar ? identical_planar_aligned : identical_diff_rotation); + bool norm_rot_tentative = !(align_planar ? identical_planar_aligned : identical_norm_rotation); + bool spec_rot_tentative = !(align_planar ? identical_planar_aligned : identical_spec_rotation); + + F32 diff_rot_deg = diff_rotation * RAD_TO_DEG; + F32 norm_rot_deg = norm_rotation * RAD_TO_DEG; + F32 spec_rot_deg = spec_rotation * RAD_TO_DEG; + + // TODO: do we need to enable/disable all these manually anymore? -Zi + /* + mCtrlTexRot->setEnabled(editable && has_material); + + mCtrlShinyRot->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls); + mCtrlBumpyRot->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls); + */ + + mCtrlTexRot->setTentative(diff_rot_tentative); + mCtrlBumpyRot->setTentative(LLSD(norm_rot_tentative)); + mCtrlShinyRot->setTentative(LLSD(spec_rot_tentative)); + + mCtrlTexRot->setValue( editable ? diff_rot_deg : 0.0f); + mCtrlShinyRot->setValue(editable ? spec_rot_deg : 0.0f); + mCtrlBumpyRot->setValue(editable ? norm_rot_deg : 0.0f); + } + + { + F32 glow = 0.f; + bool identical_glow = false; + LLSelectedTE::getGlow(glow,identical_glow); + + mCtrlGlow->setValue(glow); + mCtrlGlow->setTentative(!identical_glow); + mCtrlGlow->setEnabled(editable); + } + + { + // Maps from enum to combobox entry index + mComboTexGen->selectNthItem(((S32)selected_texgen) >> 1); + + mComboTexGen->setEnabled(editable); + mComboTexGen->setTentative(!identical); + mLabelTexGen->setEnabled(editable); + } + + { + U8 fullbright_flag = 0; + bool identical_fullbright = false; + + LLSelectedTE::getFullbright(fullbright_flag,identical_fullbright); + + mCheckFullbright->setValue((S32)(fullbright_flag != 0)); + mCheckFullbright->setEnabled(editable ); + mCheckFullbright->setTentative(!identical_fullbright); + + // TODO: find a better way to do this without relying on the name -Zi + childSetEnabled("panel_material_type_media", !has_pbr_material); + LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_material_type_media " << !has_pbr_material << LL_ENDL; + } + + // Repeats per meter + { + F32 repeats_diff = 1.f; + F32 repeats_norm = 1.f; + F32 repeats_spec = 1.f; + + bool identical_diff_repeats = false; + bool identical_norm_repeats = false; + bool identical_spec_repeats = false; + + LLSelectedTE::getMaxDiffuseRepeats(repeats_diff, identical_diff_repeats); + LLSelectedTEMaterial::getMaxNormalRepeats(repeats_norm, identical_norm_repeats); + LLSelectedTEMaterial::getMaxSpecularRepeats(repeats_spec, identical_spec_repeats); + + S32 index = mComboTexGen->getCurrentIndex(); + bool enabled = editable && (index != 1); + bool identical_repeats = true; + + S32 material_selection = getCurrentMaterialType(); + F32 repeats = 1.0f; + + U32 material_type = MATTYPE_DIFFUSE; + if (material_selection == MATMEDIA_MATERIAL) + { + material_type = getCurrentMatChannel(); + } + // TODO: check if repeats per meter even apply to PBR materials -Zi + else if (material_selection == MATMEDIA_PBR) + { + enabled = editable; + material_type = getCurrentPBRChannel(); + } + + switch (material_type) + { + default: + case MATTYPE_DIFFUSE: + { + if (material_selection != MATMEDIA_PBR) + { + enabled = editable && !id.isNull(); + } + identical_repeats = identical_diff_repeats; + repeats = repeats_diff; + } + break; + + case MATTYPE_SPECULAR: + { + if (material_selection != MATMEDIA_PBR) + { + enabled = (editable && ((shiny == SHINY_TEXTURE) && !specmap_id.isNull()) + && enable_material_controls); // Materials Alignment + } + identical_repeats = identical_spec_repeats; + repeats = repeats_spec; + } + break; + + case MATTYPE_NORMAL: + { + if (material_selection != MATMEDIA_PBR) + { + enabled = (editable && ((bumpy == BUMPY_TEXTURE) && !normmap_id.isNull()) + && enable_material_controls); // Materials Alignment + } + identical_repeats = identical_norm_repeats; + repeats = repeats_norm; + } + break; + } + + bool repeats_tentative = !identical_repeats; + + if (force_set_values) + { + //onCommit, previosly edited element updates related ones + mCtrlRpt->forceSetValue(editable ? repeats : 1.0f); + } + else + { + mCtrlRpt->setValue(editable ? repeats : 1.0f); + } + mCtrlRpt->setTentative(LLSD(repeats_tentative)); + mCtrlRpt->setEnabled(!identical_planar_texgen && enabled); + } + + // Blinn-Phong Materials + { + LLMaterialPtr material; + LLSelectedTEMaterial::getCurrent(material, identical); + + mComboShininess->setTentative(!identical_spec); + mCtrlGlossiness->setTentative(!identical_spec); + mCtrlEnvironment->setTentative(!identical_spec); + mShinyColorSwatch->setTentative(!identical_spec); + + if (material && editable) + { + LL_DEBUGS("Materials") << material->asLLSD() << LL_ENDL; + + // Alpha + U32 alpha_mode = material->getDiffuseAlphaMode(); + + if (transparency > 0.f) + { //it is invalid to have any alpha mode other than blend if transparency is greater than zero ... + alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND; + } + + if (!mIsAlpha) + { // ... unless there is no alpha channel in the texture, in which case alpha mode MUST be none + alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + } + + mComboAlphaMode->selectNthItem(alpha_mode); + + mCtrlMaskCutoff->setValue(material->getAlphaMaskCutoff()); + + updateAlphaControls(); + + identical_planar_texgen = isIdenticalPlanarTexgen(); + + // Shiny (specular) + F32 offset_x, offset_y, repeat_x, repeat_y, rot; + + mShinyTextureCtrl->setImageAssetID(material->getSpecularID()); + + if (material->getSpecularID().notNull() && (shiny == SHINY_TEXTURE)) + { + material->getSpecularOffset(offset_x,offset_y); + material->getSpecularRepeat(repeat_x,repeat_y); + + if (identical_planar_texgen) + { + repeat_x *= 2.0f; + repeat_y *= 2.0f; + } + + rot = material->getSpecularRotation(); + mCtrlShinyScaleU->setValue(repeat_x); + mCtrlShinyScaleV->setValue(repeat_y); + mCtrlShinyRot->setValue(rot*RAD_TO_DEG); + mCtrlShinyOffsetU->setValue(offset_x); + mCtrlShinyOffsetV->setValue(offset_y); + mCtrlGlossiness->setValue(material->getSpecularLightExponent()); + mCtrlEnvironment->setValue(material->getEnvironmentIntensity()); + + updateShinyControls(!material->getSpecularID().isNull(), true); + } + + // Assert desired colorswatch color to match material AFTER updateShinyControls + // to avoid getting overwritten with the default on some UI state changes. + // + if (material->getSpecularID().notNull()) + { + LLColor4 new_color = material->getSpecularLightColor(); + LLColor4 old_color = mShinyColorSwatch->get(); + + mShinyColorSwatch->setOriginal(new_color); + mShinyColorSwatch->set(new_color, force_set_values || old_color != new_color || !editable); + } + + // Bumpy (normal) + mBumpyTextureCtrl->setImageAssetID(material->getNormalID()); + + if (material->getNormalID().notNull()) + { + material->getNormalOffset(offset_x,offset_y); + material->getNormalRepeat(repeat_x,repeat_y); + + if (identical_planar_texgen) + { + repeat_x *= 2.0f; + repeat_y *= 2.0f; + } + + rot = material->getNormalRotation(); + mCtrlBumpyScaleU->setValue(repeat_x); + mCtrlBumpyScaleV->setValue(repeat_y); + mCtrlBumpyRot->setValue(rot*RAD_TO_DEG); + mCtrlBumpyOffsetU->setValue(offset_x); + mCtrlBumpyOffsetV->setValue(offset_y); + + updateBumpyControls(!material->getNormalID().isNull(), true); + } + } + } + + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + bool single_volume = (selected_count == 1); + mBtnCopyFaces->setEnabled(editable && single_volume); + mBtnPasteFaces->setEnabled(editable && !mClipboardParams.emptyMap() && (mClipboardParams.has("color") || mClipboardParams.has("texture"))); + + // Set variable values for numeric expressions + LLCalc* calcp = LLCalc::getInstance(); + calcp->setVar(LLCalc::TEX_U_SCALE, getCurrentTextureScaleU()); + calcp->setVar(LLCalc::TEX_V_SCALE, getCurrentTextureScaleV()); + calcp->setVar(LLCalc::TEX_U_OFFSET, getCurrentTextureOffsetU()); + calcp->setVar(LLCalc::TEX_V_OFFSET, getCurrentTextureOffsetV()); + calcp->setVar(LLCalc::TEX_ROTATION, getCurrentTextureRot()); + calcp->setVar(LLCalc::TEX_TRANSPARENCY, mCtrlColorTransp->getValue().asReal()); + calcp->setVar(LLCalc::TEX_GLOW, mCtrlGlow->getValue().asReal()); + + // Find all faces with same texture + // TODO: these were not yet added to the new texture panel -Zi + /* + getChild("btn_select_same_diff")->setEnabled(LLSelectMgr::getInstance()->getTEMode() && mTextureCtrl->getEnabled()); + getChild("btn_select_same_norm")->setEnabled(LLSelectMgr::getInstance()->getTEMode() && mBumpyTextureCtrl->getEnabled()); + getChild("btn_select_same_spec")->setEnabled(LLSelectMgr::getInstance()->getTEMode() && mShinyTextureCtrl->getEnabled()); + */ + } + else + { + // we can not edit this object's faces or there is no object selected, so + // we can just as well blank out the whole thing. -Zi + gSavedSettings.setBOOL("FSInternalCanEditObjectFaces", false); + LL_DEBUGS("ENABLEDISABLETOOLS") << "hide face edit controls" << LL_ENDL; + } +} + +// One-off listener that updates the build floater UI when the agent inventory adds or removes an item +// TODO: CHECK - Why do we even have this? -Zi +class PBRPickerAgentListener : public LLInventoryObserver +{ +protected: + bool mChangePending = true; +public: + PBRPickerAgentListener() : LLInventoryObserver() + { + gInventory.addObserver(this); + } + + const bool isListening() + { + return mChangePending; + } + + void changed(U32 mask) override + { + if (!(mask & (ADD | REMOVE))) + { + return; + } + + if (gFloaterTools) + { + gFloaterTools->dirty(); + } + gInventory.removeObserver(this); + mChangePending = false; + } + + ~PBRPickerAgentListener() override + { + gInventory.removeObserver(this); + mChangePending = false; + } +}; + +// One-off listener that updates the build floater UI when the prim inventory updates +// TODO: CHECK - Why do we even have this? -Zi +class PBRPickerObjectListener : public LLVOInventoryListener +{ + protected: + LLViewerObject* mObjectp; + bool mChangePending = true; + + public: + PBRPickerObjectListener(LLViewerObject* object) + : mObjectp(object) + { + registerVOInventoryListener(mObjectp, nullptr); + } + + const bool isListeningFor(const LLViewerObject* objectp) const + { + return mChangePending && (objectp == mObjectp); + } + + void inventoryChanged(LLViewerObject* object, + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void* user_data) override + { + if (gFloaterTools) + { + gFloaterTools->dirty(); + } + removeVOInventoryListener(); + mChangePending = false; + } + + ~PBRPickerObjectListener() + { + removeVOInventoryListener(); + mChangePending = false; + } +}; + +void FSPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool& has_faces_without_pbr, bool force_set_values) +{ + const bool has_pbr_capabilities = LLMaterialEditor::capabilitiesAvailable(); + + mTabsPBRMatMedia->enableTabButton( + mTabsPBRMatMedia->getIndexForPanel( + mTabsPBRMatMedia->getPanelByName("panel_material_type_pbr")), has_pbr_capabilities); + LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_material_type_pbr " << has_pbr_capabilities << LL_ENDL; + + LLSelectedTEGetmatId func; + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func); + + has_pbr_material = func.mHasFacesWithPBR; + has_faces_without_pbr = func.mHasFacesWithoutPBR; + + // this could just be saved in the class instead of fetching it again after updateUI() already did -Zi + const bool settable = has_pbr_capabilities && objectp->permModify() && !objectp->isPermanentEnforced(); // do not depend on non-PBR here so we can turn any face into PBR -Zi + const bool editable = LLMaterialEditor::canModifyObjectsMaterial() && !has_faces_without_pbr; + const bool saveable = LLMaterialEditor::canSaveObjectsMaterial() && !has_faces_without_pbr; + + mMaterialCtrlPBR->setEnabled(settable); + mMaterialCtrlPBR->setTentative(!func.mIdenticalMaterial); + mMaterialCtrlPBR->setImageAssetID(func.mMaterialId); + LL_DEBUGS("ENABLEDISABLETOOLS") << "mMaterialCtrlPBR " << settable << LL_ENDL; + + LL_DEBUGS("ENABLEDISABLETOOLS") << "PBR controls overall: " << editable << LL_ENDL; + + mBaseTexturePBR->setEnabled(editable); + mBaseTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] : LLUUID::null); + mBaseTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]); + + mBaseTintPBR->setEnabled(editable); + + mBaseTintPBR->set(srgbColor4(func.mMaterialSummary.mBaseColor)); + mBaseTintPBR->setTentative(!func.mIdenticalBaseColor); // TODO: split alpha from color? -Zi + mBaseTintPBR->setValid(editable); + LL_DEBUGS("ENABLEDISABLETOOLS") << "mBaseTintPBR valid " << editable << LL_ENDL; + mBaseTintPBR->setFallbackImage(LLUI::getUIImage("locked_image.j2c") ); + + mNormalTexturePBR->setEnabled(editable); + mNormalTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] : LLUUID::null); + mNormalTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]); + + mORMTexturePBR->setEnabled(editable); + mORMTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] : LLUUID::null); + mORMTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]); + + mEmissiveTexturePBR->setEnabled(editable); + mEmissiveTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] : LLUUID::null); + mEmissiveTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]); + + mEmissiveTintPBR->setEnabled(editable); + mEmissiveTintPBR->set(srgbColor4(func.mMaterialSummary.mEmissiveColor)); + mEmissiveTintPBR->setTentative(!func.mIdenticalEmissive); + mEmissiveTintPBR->setValid(editable); + LL_DEBUGS("ENABLEDISABLETOOLS") << "mEmissiveTintPBR valid " << editable << LL_ENDL; + mEmissiveTintPBR->setFallbackImage(LLUI::getUIImage("locked_image.j2c") ); + + mCheckDoubleSidedPBR->setEnabled(editable); + mCheckDoubleSidedPBR->setValue(func.mMaterialSummary.mDoubleSided); + mCheckDoubleSidedPBR->setTentative(!func.mIdenticalDoubleSided); + + mAlphaPBR->setEnabled(editable); + mAlphaPBR->setValue(func.mMaterialSummary.mBaseColor.mV[VALPHA]); + mAlphaPBR->setTentative(!func.mIdenticalBaseColor); // TODO: split alpha from color? -Zi + + mAlphaModePBR->setEnabled(editable); + mAlphaModePBR->setValue(func.mMaterialSummary.getAlphaMode()); + mAlphaModePBR->setTentative(!func.mIdenticalAlphaMode); + mLabelAlphaModePBR->setEnabled(editable); + + mMaskCutoffPBR->setEnabled(editable); + mMaskCutoffPBR->setValue(func.mMaterialSummary.mAlphaCutoff); + mMaskCutoffPBR->setTentative(!func.mIdenticalAlphaCutoff); + + mMetallicFactorPBR->setEnabled(editable); + mMetallicFactorPBR->setValue(func.mMaterialSummary.mMetallicFactor); + mMetallicFactorPBR->setTentative(!func.mIdenticalMetallic); + + mRoughnessFactorPBR->setEnabled(editable); + mRoughnessFactorPBR->setValue(func.mMaterialSummary.mRoughnessFactor); + mRoughnessFactorPBR->setTentative(!func.mIdenticalRoughness); + + if (func.mMaterial) + { + mPBRBaseMaterialParams.mMap = func.mMaterial->mTextureId; + mPBRBaseMaterialParams.mBaseColorTint = srgbColor4(func.mMaterial->mBaseColor); + mPBRBaseMaterialParams.mMetallic = func.mMaterial->mMetallicFactor; + mPBRBaseMaterialParams.mRoughness = func.mMaterial->mRoughnessFactor; + mPBRBaseMaterialParams.mEmissiveTint = func.mMaterial->mEmissiveColor; + mPBRBaseMaterialParams.mAlphaMode = func.mMaterial->mAlphaMode; + mPBRBaseMaterialParams.mAlphaCutoff = func.mMaterial->mAlphaCutoff; + mPBRBaseMaterialParams.mDoubleSided = func.mMaterial->mDoubleSided; + } + + if (objectp->isAttachment()) + { + // TODO: coming in from latest patch, seems broken? + mMaterialCtrlPBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER | PERM_MODIFY); + // TODO: before: + // mMaterialCtrlPBR->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER | PERM_MODIFY); + } + else + { + mMaterialCtrlPBR->setImmediateFilterPermMask(PERM_NONE); + } + + mBtnSavePBR->setEnabled(saveable); // TODO: flag for "something is not identical" -Zi && pbr_identical); + LL_DEBUGS("ENABLEDISABLETOOLS") << "mBtnSavePBR " << saveable << LL_ENDL; + + // TODO: CHECK - Find out if we need this at all -Zi + if (objectp->isInventoryPending()) + { + // Reuse the same listener when possible + if (!mVOInventoryListener || !mVOInventoryListener->isListeningFor(objectp)) + { + mVOInventoryListener = std::make_unique(objectp); + } + } + else + { + mVOInventoryListener = nullptr; + } + if (!func.mIdenticalMaterial || func.mMaterialId.isNull() || func.mMaterialId == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID) + { + mAgentInventoryListener = nullptr; + } + else + { + if (!mAgentInventoryListener || !mAgentInventoryListener->isListening()) + { + mAgentInventoryListener = std::make_unique(); + } + } + + // Control values will be set once per frame in setMaterialOverridesFromSelection + sMaterialOverrideSelection.setDirty(); +} + +void FSPanelFace::updateCopyTexButton() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + mBtnCopyFaces->setEnabled(objectp && objectp->getPCode() == LL_PCODE_VOLUME && objectp->permModify() + && !objectp->isPermanentEnforced() && !objectp->isInventoryPending() + && (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1) + && LLMaterialEditor::canClipboardObjectsMaterial()); + std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options"); + mBtnCopyFaces->setToolTip(tooltip); +} + +void FSPanelFace::refresh() +{ + LL_DEBUGS("Materials") << LL_ENDL; + getState(); +} + +void FSPanelFace::refreshMedia() +{ + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + LLViewerObject* first_object = selected_objects->getFirstObject(); + + if (!(first_object + && first_object->getPCode() == LL_PCODE_VOLUME + && first_object->permModify() + )) + { + mBtnAddMedia->setEnabled(false); + mTitleMediaText->clear(); + clearMediaSettings(); + return; + } + + std::string url = first_object->getRegion()->getCapability("ObjectMedia"); + bool has_media_capability = (!url.empty()); + + if (!has_media_capability) + { + mBtnAddMedia->setEnabled(false); + LL_WARNS("LLFloaterToolsMedia") << "Media not enabled (no capability) in this region!" << LL_ENDL; + clearMediaSettings(); + return; + } + + bool is_nonpermanent_enforced = (LLSelectMgr::getInstance()->getSelection()->getFirstRootNode() + && LLSelectMgr::getInstance()->selectGetRootsNonPermanentEnforced()) + || LLSelectMgr::getInstance()->selectGetNonPermanentEnforced(); + bool editable = is_nonpermanent_enforced && (first_object->permModify() || selectedMediaEditable()); + + // Check modify permissions and whether any selected objects are in + // the process of being fetched. If they are, then we're not editable + if (editable) + { + LLObjectSelection::iterator iter = selected_objects->begin(); + LLObjectSelection::iterator end = selected_objects->end(); + for (; iter != end; ++iter) + { + LLSelectNode* node = *iter; + LLVOVolume* object = dynamic_cast(node->getObject()); + if (object && !object->permModify()) + { + LL_INFOS("LLFloaterToolsMedia") + << "Selection not editable due to lack of modify permissions on object id " + << object->getID() << LL_ENDL; + + editable = false; + break; + } + } + } + + // Media settings + bool bool_has_media = false; + struct media_functor : public LLSelectedTEGetFunctor + { + bool get(LLViewerObject* object, S32 face) + { + LLTextureEntry *te = object->getTE(face); + if (te) + { + return te->hasMedia(); + } + return false; + } + } func; + + // check if all faces have media (or, all don't have media) + LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo = selected_objects->getSelectedTEValue(&func, bool_has_media); + + const LLMediaEntry default_media_data; + + struct functor_getter_media_data : public LLSelectedTEGetFunctor< LLMediaEntry> + { + functor_getter_media_data(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + LLMediaEntry get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return *(object->getTE(face)->getMediaData()); + } + return mMediaEntry; + }; + + const LLMediaEntry& mMediaEntry; + + } func_media_data(default_media_data); + + LLMediaEntry media_data_get; + LLFloaterMediaSettings::getInstance()->mMultipleMedia = !(selected_objects->getSelectedTEValue(&func_media_data, media_data_get)); + + std::string multi_media_info_str = LLTrans::getString("Multiple Media"); + std::string media_title = ""; + + // update UI depending on whether "object" (prim or face) has media + // and whether or not you are allowed to edit it. + + mBtnAddMedia->setEnabled(editable); + + // IF all the faces have media (or all don't have media) + if (LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo) + { + // TODO: get media title and set it. + mTitleMediaText->clear(); + + // if identical is set, all faces are same (whether all empty or has the same media) + if (!(LLFloaterMediaSettings::getInstance()->mMultipleMedia)) + { + // media data is valid + if (media_data_get != default_media_data) + { + // initial media title is the media URL (until we get the name) + media_title = media_data_get.getHomeURL(); + } + // else all faces might be empty + } + else // there are Different media been set on on the faces + { + media_title = multi_media_info_str; + } + + mBtnDeleteMedia->setEnabled(bool_has_media && editable); + + // TODO: display a list of all media on the face - use 'identical' flag + } + else // not all faces have media but at least one does + { + // selected faces have not identical value + LLFloaterMediaSettings::getInstance()->mMultipleValidMedia = selected_objects->isMultipleTEValue(&func_media_data, default_media_data); + + if (LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) + { + media_title = multi_media_info_str; + } + else + { + // Media data is valid + if (media_data_get != default_media_data) + { + // initial media title is the media URL (until we get the name) + media_title = media_data_get.getHomeURL(); + } + } + + mBtnDeleteMedia->setEnabled(TRUE); + } + + S32 materials_media = getCurrentMaterialType(); + if (materials_media == MATMEDIA_MEDIA) + { + // currently displaying media info, navigateTo and update title + navigateToTitleMedia(media_title); + } + else + { + // Media can be heavy, don't keep it around + // MAC specific: MAC doesn't support setVolume(0) so if not + // unloaded, it might keep playing audio until user closes editor + unloadMedia(); + mNeedMediaTitle = false; + } + + mTitleMediaText->setText(media_title); + + // load values for media settings + updateMediaSettings(); + + LLFloaterMediaSettings::initValues(mMediaSettings, editable); +} + +void FSPanelFace::unloadMedia() +{ + // destroy media source used to grab media title + mTitleMedia->unloadMediaSource(); +} + +void FSPanelFace::onMaterialOverrideReceived(const LLUUID& object_id, S32 side) +{ + sMaterialOverrideSelection.onSelectedObjectUpdated(object_id, side); +} + +////////////////////////////////////////////////////////////////////////////// +// +void FSPanelFace::navigateToTitleMedia(const std::string url) +{ + std::string multi_media_info_str = LLTrans::getString("Multiple Media"); + if (url.empty() || multi_media_info_str == url) + { + // nothing to show + mNeedMediaTitle = false; + } + else + { + LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin(); + + // check if url changed or if we need a new media source + if (mTitleMedia->getCurrentNavUrl() != url || media_plugin == nullptr) + { + mTitleMedia->navigateTo(url); + + LLViewerMediaImpl* impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mTitleMedia->getTextureID()); + if (impl) + { + // if it's a page with a movie, we don't want to hear it + impl->setVolume(0); + } + } + + // flag that we need to update the title (even if no request were made) + mNeedMediaTitle = true; + } +} + +bool FSPanelFace::selectedMediaEditable() +{ + U32 owner_mask_on; + U32 owner_mask_off; + U32 valid_owner_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_OWNER, + &owner_mask_on, &owner_mask_off); + U32 group_mask_on; + U32 group_mask_off; + U32 valid_group_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_GROUP, + &group_mask_on, &group_mask_off); + U32 everyone_mask_on; + U32 everyone_mask_off; + S32 valid_everyone_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_EVERYONE, + &everyone_mask_on, &everyone_mask_off); + + bool selected_Media_editable = false; + + // if perms we got back are valid + if (valid_owner_perms && + valid_group_perms && + valid_everyone_perms) + { + if ((owner_mask_on & PERM_MODIFY) || + (group_mask_on & PERM_MODIFY) || + (everyone_mask_on & PERM_MODIFY)) + { + selected_Media_editable = true; + } + else + { + // user is NOT allowed to press the RESET button + selected_Media_editable = false; + }; + }; + + return selected_Media_editable; +} + +void FSPanelFace::clearMediaSettings() +{ + LLFloaterMediaSettings::clearValues(false); +} + +void FSPanelFace::updateMediaSettings() +{ + bool identical(false); + std::string base_key(""); + std::string value_str(""); + int value_int = 0; + bool value_bool = false; + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + // TODO: (CP) refactor this using something clever or boost or both !! + + const LLMediaEntry default_media_data; + + // controls + U8 value_u8 = default_media_data.getControls(); + struct functor_getter_controls : public LLSelectedTEGetFunctor + { + functor_getter_controls(const LLMediaEntry &entry) : mMediaEntry(entry) {} + + U8 get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getControls(); + } + return mMediaEntry.getControls(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_controls(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_controls, value_u8); + base_key = std::string(LLMediaEntry::CONTROLS_KEY); + mMediaSettings[base_key] = value_u8; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // First click (formerly left click) + value_bool = default_media_data.getFirstClickInteract(); + struct functor_getter_first_click : public LLSelectedTEGetFunctor + { + functor_getter_first_click(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getFirstClickInteract(); + } + return mMediaEntry.getFirstClickInteract(); + }; + + const LLMediaEntry &mMediaEntry; + } func_first_click(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_first_click, value_bool); + base_key = std::string(LLMediaEntry::FIRST_CLICK_INTERACT_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Home URL + value_str = default_media_data.getHomeURL(); + struct functor_getter_home_url : public LLSelectedTEGetFunctor + { + functor_getter_home_url(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + std::string get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getHomeURL(); + } + return mMediaEntry.getHomeURL(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_home_url(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_home_url, value_str); + base_key = std::string(LLMediaEntry::HOME_URL_KEY); + mMediaSettings[base_key] = value_str; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Current URL + value_str = default_media_data.getCurrentURL(); + struct functor_getter_current_url : public LLSelectedTEGetFunctor + { + functor_getter_current_url(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + std::string get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getCurrentURL(); + } + return mMediaEntry.getCurrentURL(); + }; + + const LLMediaEntry &mMediaEntry; + } func_current_url(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_current_url, value_str); + base_key = std::string(LLMediaEntry::CURRENT_URL_KEY); + mMediaSettings[base_key] = value_str; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Auto zoom + value_bool = default_media_data.getAutoZoom(); + struct functor_getter_auto_zoom : public LLSelectedTEGetFunctor + { + functor_getter_auto_zoom(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getAutoZoom(); + } + return mMediaEntry.getAutoZoom(); + }; + + const LLMediaEntry &mMediaEntry; + } func_auto_zoom(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_auto_zoom, value_bool); + base_key = std::string(LLMediaEntry::AUTO_ZOOM_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Auto play + //value_bool = default_media_data.getAutoPlay(); + // set default to auto play TRUE -- angela EXT-5172 + value_bool = true; + struct functor_getter_auto_play : public LLSelectedTEGetFunctor + { + functor_getter_auto_play(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getAutoPlay(); + } + //return mMediaEntry.getAutoPlay(); set default to auto play TRUE -- angela EXT-5172 + return true; + }; + + const LLMediaEntry &mMediaEntry; + + } func_auto_play(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_auto_play, value_bool); + base_key = std::string(LLMediaEntry::AUTO_PLAY_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + + // Auto scale + // set default to auto scale TRUE -- angela EXT-5172 + //value_bool = default_media_data.getAutoScale(); + value_bool = true; + struct functor_getter_auto_scale : public LLSelectedTEGetFunctor + { + functor_getter_auto_scale(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getAutoScale(); + } + // return mMediaEntry.getAutoScale(); set default to auto scale TRUE -- angela EXT-5172 + return true; + }; + + const LLMediaEntry &mMediaEntry; + + } func_auto_scale(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_auto_scale, value_bool); + base_key = std::string(LLMediaEntry::AUTO_SCALE_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Auto loop + value_bool = default_media_data.getAutoLoop(); + struct functor_getter_auto_loop : public LLSelectedTEGetFunctor + { + functor_getter_auto_loop(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getAutoLoop(); + } + return mMediaEntry.getAutoLoop(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_auto_loop(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_auto_loop, value_bool); + base_key = std::string(LLMediaEntry::AUTO_LOOP_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // width pixels (if not auto scaled) + value_int = default_media_data.getWidthPixels(); + struct functor_getter_width_pixels : public LLSelectedTEGetFunctor + { + functor_getter_width_pixels(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + int get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getWidthPixels(); + } + return mMediaEntry.getWidthPixels(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_width_pixels(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_width_pixels, value_int); + base_key = std::string(LLMediaEntry::WIDTH_PIXELS_KEY); + mMediaSettings[base_key] = value_int; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // height pixels (if not auto scaled) + value_int = default_media_data.getHeightPixels(); + struct functor_getter_height_pixels : public LLSelectedTEGetFunctor + { + functor_getter_height_pixels(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + int get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getHeightPixels(); + } + return mMediaEntry.getHeightPixels(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_height_pixels(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_height_pixels, value_int); + base_key = std::string(LLMediaEntry::HEIGHT_PIXELS_KEY); + mMediaSettings[base_key] = value_int; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Enable Alt image + value_bool = default_media_data.getAltImageEnable(); + struct functor_getter_enable_alt_image : public LLSelectedTEGetFunctor + { + functor_getter_enable_alt_image(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getAltImageEnable(); + } + return mMediaEntry.getAltImageEnable(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_enable_alt_image(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_enable_alt_image, value_bool); + base_key = std::string(LLMediaEntry::ALT_IMAGE_ENABLE_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - owner interact + value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_OWNER); + struct functor_getter_perms_owner_interact : public LLSelectedTEGetFunctor + { + functor_getter_perms_owner_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_OWNER)); + } + return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_OWNER); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_owner_interact(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_perms_owner_interact, value_bool); + base_key = std::string(LLPanelContents::PERMS_OWNER_INTERACT_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - owner control + value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_OWNER); + struct functor_getter_perms_owner_control : public LLSelectedTEGetFunctor + { + functor_getter_perms_owner_control(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_OWNER)); + } + return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_OWNER); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_owner_control(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_perms_owner_control, value_bool); + base_key = std::string(LLPanelContents::PERMS_OWNER_CONTROL_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - group interact + value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_GROUP); + struct functor_getter_perms_group_interact : public LLSelectedTEGetFunctor + { + functor_getter_perms_group_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_GROUP)); + } + return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_GROUP); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_group_interact(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_perms_group_interact, value_bool); + base_key = std::string(LLPanelContents::PERMS_GROUP_INTERACT_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - group control + value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_GROUP); + struct functor_getter_perms_group_control : public LLSelectedTEGetFunctor + { + functor_getter_perms_group_control(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_GROUP)); + } + return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_GROUP); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_group_control(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_perms_group_control, value_bool); + base_key = std::string(LLPanelContents::PERMS_GROUP_CONTROL_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - anyone interact + value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_ANYONE); + struct functor_getter_perms_anyone_interact : public LLSelectedTEGetFunctor + { + functor_getter_perms_anyone_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_ANYONE)); + } + return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_ANYONE); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_anyone_interact(default_media_data); + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func_perms_anyone_interact, value_bool); + base_key = std::string(LLPanelContents::PERMS_ANYONE_INTERACT_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - anyone control + value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_ANYONE); + struct functor_getter_perms_anyone_control : public LLSelectedTEGetFunctor + { + functor_getter_perms_anyone_control(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_ANYONE)); + } + return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_ANYONE); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_anyone_control(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_perms_anyone_control, value_bool); + base_key = std::string(LLPanelContents::PERMS_ANYONE_CONTROL_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // security - whitelist enable + value_bool = default_media_data.getWhiteListEnable(); + struct functor_getter_whitelist_enable : public LLSelectedTEGetFunctor + { + functor_getter_whitelist_enable(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getWhiteListEnable(); + } + return mMediaEntry.getWhiteListEnable(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_whitelist_enable(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_whitelist_enable, value_bool); + base_key = std::string(LLMediaEntry::WHITELIST_ENABLE_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // security - whitelist URLs + std::vector value_vector_str = default_media_data.getWhiteList(); + struct functor_getter_whitelist_urls : public LLSelectedTEGetFunctor> + { + functor_getter_whitelist_urls(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + std::vector get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getWhiteList(); + } + return mMediaEntry.getWhiteList(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_whitelist_urls(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_whitelist_urls, value_vector_str); + base_key = std::string(LLMediaEntry::WHITELIST_KEY); + mMediaSettings[base_key].clear(); + + std::vector< std::string >::iterator iter = value_vector_str.begin(); + while (iter != value_vector_str.end()) + { + std::string white_list_url = *iter; + mMediaSettings[base_key].append(white_list_url); + ++iter; + }; + + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; +} + +void FSPanelFace::updateMediaTitle() +{ + // only get the media name if we need it + if (!mNeedMediaTitle) + { + return; + } + + // get plugin impl + LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin(); + if (media_plugin && mTitleMedia->getCurrentNavUrl() == media_plugin->getNavigateURI()) + { + // get the media name (asynchronous - must call repeatedly) + std::string media_title = media_plugin->getMediaName(); + + // only replace the title if what we get contains something + if (!media_title.empty()) + { + // update the UI widget + mTitleMediaText->setText(media_title); + + // stop looking for a title when we get one + mNeedMediaTitle = false; + } + } +} + +void FSPanelFace::onCommitColor() +{ + sendColor(); +} + +void FSPanelFace::onCommitShinyColor() +{ + LLSelectedTEMaterial::setSpecularLightColor(this, mShinyColorSwatch->get()); +} + +void FSPanelFace::onCommitAlpha() +{ + sendAlpha(); +} + +void FSPanelFace::onCancelColor() +{ + LLSelectMgr::getInstance()->selectionRevertColors(); +} + +void FSPanelFace::onCancelShinyColor() +{ + LLSelectMgr::getInstance()->selectionRevertShinyColors(); +} + +void FSPanelFace::onSelectColor() +{ + LLSelectMgr::getInstance()->saveSelectedObjectColors(); + sendColor(); +} + +void FSPanelFace::onSelectShinyColor() +{ + LLSelectedTEMaterial::setSpecularLightColor(this, mShinyColorSwatch->get()); + LLSelectMgr::getInstance()->saveSelectedShinyColors(); +} + +void FSPanelFace::updateVisibility(LLViewerObject* objectp /* = nullptr */) +{ + updateAlphaControls(); + // TODO: is this still needed? -Zi + updateShinyControls(); + updateBumpyControls(); + + // Find all faces with same texture + // TODO: is this still needed? -Zi Probably not but we don't have these buttons yet anyway -Zi + /* + getChild("btn_select_same_diff")->setVisible(mTextureCtrl->getVisible()); + getChild("btn_select_same_norm")->setVisible(mBumpyTextureCtrl->getVisible()); + getChild("btn_select_same_spec")->setVisible(mShinyTextureCtrl->getVisible()); + */ +} + +void FSPanelFace::onCommitBump() +{ + sendBump(mComboBumpiness->getCurrentIndex()); +} + +void FSPanelFace::onCommitTexGen() +{ + sendTexGen(); +} + +void FSPanelFace::updateShinyControls(bool is_setting_texture, bool mess_with_shiny_combobox) +{ + LLUUID shiny_texture_ID = mShinyTextureCtrl->getImageAssetID(); + LL_DEBUGS("Materials") << "Shiny texture selected: " << shiny_texture_ID << LL_ENDL; + + if(mess_with_shiny_combobox) + { + if (shiny_texture_ID.notNull() && is_setting_texture) + { + if (!mComboShininess->itemExists(USE_TEXTURE_LABEL)) + { + mComboShininess->add(USE_TEXTURE_LABEL); + } + mComboShininess->setSimple(USE_TEXTURE_LABEL); + } + else + { + if (mComboShininess->itemExists(USE_TEXTURE_LABEL)) + { + mComboShininess->remove(SHINY_TEXTURE); + mComboShininess->selectFirstItem(); + } + } + } + else + { + if (shiny_texture_ID.isNull() && mComboShininess->itemExists(USE_TEXTURE_LABEL)) + { + mComboShininess->remove(SHINY_TEXTURE); + mComboShininess->selectFirstItem(); + } + } + + mShinyColorSwatch->setValid(shiny_texture_ID.notNull()); + LL_DEBUGS("ENABLEDISABLETOOLS") << "mShinyColorSwatch valid " << shiny_texture_ID.notNull() << LL_ENDL; + mShinyColorSwatch->setFallbackImage(LLUI::getUIImage("locked_image.j2c")); + + gSavedSettings.setBOOL("FSInternalFaceHasBPSpecularMap", shiny_texture_ID.notNull()); + + LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_blinn_phong_specular " << shiny_texture_ID.notNull() << LL_ENDL; +} + +void FSPanelFace::updateBumpyControls(bool is_setting_texture, bool mess_with_combobox) +{ + LLUUID bumpy_texture_ID = mBumpyTextureCtrl->getImageAssetID(); + LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL; + + if (mess_with_combobox) + { + LLUUID bumpy_texture_ID = mBumpyTextureCtrl->getImageAssetID(); + LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL; + + if (bumpy_texture_ID.notNull() && is_setting_texture) + { + if (!mComboBumpiness->itemExists(USE_TEXTURE_LABEL)) + { + mComboBumpiness->add(USE_TEXTURE_LABEL); + } + mComboBumpiness->setSimple(USE_TEXTURE_LABEL); + } + else + { + if (mComboBumpiness->itemExists(USE_TEXTURE_LABEL)) + { + mComboBumpiness->remove(BUMPY_TEXTURE); + mComboBumpiness->selectFirstItem(); + } + } + } + + gSavedSettings.setBOOL("FSInternalFaceHasBPNormalMap", bumpy_texture_ID.notNull()); + + LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_blinn_phong_normal " << bumpy_texture_ID.notNull() << LL_ENDL; +} + +void FSPanelFace::onCommitShiny() +{ + sendShiny(mComboShininess->getCurrentIndex()); +} + +void FSPanelFace::updateAlphaControls() +{ + mCtrlMaskCutoff->setEnabled(getCurrentDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK); +} + +void FSPanelFace::onCommitAlphaMode() +{ + updateAlphaControls(); + LLSelectedTEMaterial::setDiffuseAlphaMode(this, getCurrentDiffuseAlphaMode()); +} + +void FSPanelFace::onCommitFullbright() +{ + sendFullbright(); +} + +void FSPanelFace::onCommitGlow() +{ + sendGlow(); +} + +// +// PBR +// + +// Get a dump of the json representation of the current state of the editor UI +// in GLTF format, excluding transforms as they are not supported in material +// assets. (See also LLGLTFMaterial::sanitizeAssetMaterial()) +void FSPanelFace::getGLTFMaterial(LLGLTFMaterial* mat) +{ + mat->mBaseColor = linearColor4(LLColor4(mBaseTintPBR->get())); + mat->mBaseColor.mV[VALPHA] = mAlphaPBR->get(); + + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] = mBaseTexturePBR->getImageAssetID(); + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] = mNormalTexturePBR->getImageAssetID(); + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] = mORMTexturePBR->getImageAssetID(); + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] = mEmissiveTexturePBR->getImageAssetID(); + + mat->mEmissiveColor = linearColor4(LLColor4(mEmissiveTintPBR->get())); + + mat->mMetallicFactor = mMetallicFactorPBR->get(); + mat->mRoughnessFactor = mRoughnessFactorPBR->get(); + + mat->mDoubleSided = mCheckDoubleSidedPBR->get(); + mat->setAlphaMode(mAlphaModePBR->getValue().asString()); + mat->mAlphaCutoff = mMaskCutoffPBR->getValue().asReal(); +} + +BOOL FSPanelFace::onDragPbr(LLInventoryItem* item) +{ + bool accept = true; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if (!LLToolDragAndDrop::isInventoryDropAcceptable(obj, item)) + { + accept = false; + break; + } + } + return accept; +} + +void FSPanelFace::onCommitPbr() +{ + if (!mMaterialCtrlPBR->getTentative()) + { + // we grab the item id first, because we want to do a + // permissions check in the selection manager. ARGH! + LLUUID id = mMaterialCtrlPBR->getImageItemID(); + if (id.isNull()) + { + id = mMaterialCtrlPBR->getImageAssetID(); + } + if (!LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id)) + { + // If failed to set material, refresh mMaterialCtrlPBR's value + refresh(); + } + } +} + +void FSPanelFace::onCancelPbr() +{ + LLSelectMgr::getInstance()->selectionRevertGLTFMaterials(); +} + +void FSPanelFace::onSelectPbr() +{ + LLSelectMgr::getInstance()->saveSelectedObjectTextures(); + onCommitPbr(); +} + +void FSPanelFace::onCommitPbr(const LLUICtrl* pbr_ctrl) +{ + LL_WARNS("FACEPANELM") << "committed pbr map " << pbr_ctrl->getName() << LL_ENDL; + + if (pbr_ctrl == mBaseTexturePBR) + { + mUnsavedChanges |= MATERIAL_BASE_COLOR_TEX_DIRTY; + } + else if (pbr_ctrl == mNormalTexturePBR) + { + mUnsavedChanges |= MATERIAL_NORMAL_TEX_DIRTY; + } + else if (pbr_ctrl == mEmissiveTexturePBR) + { + mUnsavedChanges |= MATERIAL_EMISIVE_TEX_DIRTY; + } + else if (pbr_ctrl == mORMTexturePBR) + { + mUnsavedChanges |= MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY; + } + else if (pbr_ctrl == mBaseTintPBR) + { + mUnsavedChanges |= MATERIAL_BASE_COLOR_DIRTY; + } + else if (pbr_ctrl == mEmissiveTintPBR) + { + mUnsavedChanges |= MATERIAL_EMISIVE_COLOR_DIRTY; + } + else if (pbr_ctrl == mCheckDoubleSidedPBR) + { + mUnsavedChanges |= MATERIAL_DOUBLE_SIDED_DIRTY; + } + else if (pbr_ctrl == mAlphaPBR) + { + mUnsavedChanges |= MATERIAL_BASE_COLOR_DIRTY; + } + else if (pbr_ctrl == mAlphaModePBR) + { + mUnsavedChanges |= MATERIAL_ALPHA_MODE_DIRTY; + } + else if (pbr_ctrl == mMaskCutoffPBR) + { + mUnsavedChanges |= MATERIAL_ALPHA_CUTOFF_DIRTY; + } + else if (pbr_ctrl == mMetallicFactorPBR) + { + mUnsavedChanges |= MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY; + } + else if (pbr_ctrl == mRoughnessFactorPBR) + { + mUnsavedChanges |= MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY; + } +} + +// highlights PBR material parameters that are part of a material override +void FSPanelFace::updatePBROverrideDisplay() +{ + LLColor4 labelTextColor = LLUIColorTable::instance().getColor("LabelTextColor"); + LLColor4 emphasisColor = LLUIColorTable::instance().getColor("EmphasisColor"); // TODO: maybe create distinct color for skins -Zi + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + + if (!objectp || !node) + { + return; + } + + // a way to resolve situations where source and target have different amount of faces + S32 num_tes = llmin((S32)objectp->getNumTEs(), objectp->getNumFaces()); + for (S32 te = 0; te < num_tes; ++te) + { + if (!node->isTESelected(te)) + { + continue; + } + + LLTextureEntry* tep = objectp->getTE(te); + if (!tep) + { + continue; + } + + LLGLTFMaterial* override_material = tep->getGLTFMaterialOverride(); + if (!override_material) + { + continue; + } + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") + << override_material << "\n" + << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] << "\n" + << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] << "\n" + << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] << "\n" + << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] << "\n" + << override_material->mBaseColor << "\n" + << override_material->mEmissiveColor << "\n" + << override_material->mAlphaMode << "\n" + << override_material->mAlphaCutoff << "\n" + << override_material->mMetallicFactor << "\n" + << override_material->mRoughnessFactor << "\n" + << override_material->mDoubleSided << "\n" + << LL_ENDL; + + mBaseTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].isNull() ? labelTextColor : emphasisColor); + mNormalTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].isNull() ? labelTextColor : emphasisColor); + mORMTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].isNull() ? labelTextColor : emphasisColor); + mEmissiveTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].isNull() ? labelTextColor : emphasisColor); + + mBaseTintPBR->setLabelColor(override_material->mBaseColor == LLGLTFMaterial::getDefaultBaseColor() ? labelTextColor : emphasisColor); + mAlphaPBR->setLabelColor(override_material->mBaseColor == LLGLTFMaterial::getDefaultBaseColor() ? labelTextColor : emphasisColor); + mLabelAlphaModePBR->setColor(override_material->mAlphaMode == LLGLTFMaterial::getDefaultAlphaMode() ? labelTextColor : emphasisColor); + mMaskCutoffPBR->setLabelColor(override_material->mAlphaCutoff == LLGLTFMaterial::getDefaultAlphaCutoff() ? labelTextColor : emphasisColor); + + mMetallicFactorPBR->setLabelColor(override_material->mMetallicFactor == LLGLTFMaterial::getDefaultMetallicFactor() ? labelTextColor : emphasisColor); + mRoughnessFactorPBR->setLabelColor(override_material->mRoughnessFactor == LLGLTFMaterial::getDefaultRoughnessFactor() ? labelTextColor : emphasisColor); + + mEmissiveTintPBR->setLabelColor(override_material->mEmissiveColor == LLGLTFMaterial::getDefaultEmissiveColor() ? labelTextColor : emphasisColor); + + mCheckDoubleSidedPBR->setEnabledColor(override_material->mDoubleSided == LLGLTFMaterial::getDefaultDoubleSided() ? labelTextColor : emphasisColor); + // refresh checkbox, as LLCheckBoxCtrl does not refresh its label when you change the color + mCheckDoubleSidedPBR->setEnabled(mCheckDoubleSidedPBR->getEnabled()); + + break; + } +} + +void FSPanelFace::onCancelPbr(const LLUICtrl* map_ctrl) +{ + // TODO -Zi +} + +void FSPanelFace::onSelectPbr(const LLUICtrl* map_ctrl) +{ + onCommitPbr(map_ctrl); +} + +BOOL FSPanelFace::onDragTexture(LLInventoryItem* item) +{ + bool accept = true; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if (!LLToolDragAndDrop::isInventoryDropAcceptable(obj, item)) + { + accept = false; + break; + } + } + return accept; +} + +void FSPanelFace::onCommitTexture(const LLUICtrl* ctrl, const LLSD& data) +{ + LL_WARNS() << "onCommitTexture" << LL_ENDL; + add(LLStatViewer::EDIT_TEXTURE, 1); + + LLSelectMgr::getInstance()->saveSelectedObjectTextures(); + sendTexture(); + + LLGLenum image_format; + bool identical_image_format = false; + LLSelectedTE::getImageFormat(image_format, identical_image_format); + + U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + switch (image_format) + { + case GL_RGBA: + case GL_ALPHA: + { + alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND; + } + break; + + case GL_RGB: break; + default: + { + LL_WARNS() << "Unexpected tex format in FSPanelFace...resorting to no alpha" << LL_ENDL; + } + break; + } + + mComboAlphaMode->selectNthItem(alpha_mode); + + LLSelectedTEMaterial::setDiffuseAlphaMode(this, getCurrentDiffuseAlphaMode()); + + // can't just pass "ctrl" on because it's const, and we also need to check + // the ctrl type so we make sure it's a texture swatch + onTextureSelectionChanged(ctrl->getName()); +} + +void FSPanelFace::onCommitNormalTexture(const LLUICtrl* ctrl, const LLSD& data) +{ + LL_DEBUGS("Materials") << data << LL_ENDL; + LLUUID nmap_id = getCurrentNormalMap(); + sendBump(nmap_id.isNull() ? 0 : BUMPY_TEXTURE); + onTextureSelectionChanged(ctrl->getName()); +} + +void FSPanelFace::onCommitSpecularTexture(const LLUICtrl* ctrl, const LLSD& data) +{ + LL_DEBUGS("Materials") << data << LL_ENDL; + sendShiny(SHINY_TEXTURE); + onTextureSelectionChanged(ctrl->getName()); +} + +void FSPanelFace::onCloseTexturePicker(const LLSD& data) +{ + LL_DEBUGS("Materials") << data << LL_ENDL; + updateUI(); +} + +void FSPanelFace::onCancelTexture() +{ + LL_WARNS() << "onCancelTexture" << LL_ENDL; + LLSelectMgr::getInstance()->selectionRevertTextures(); +} + +void FSPanelFace::onCancelNormalTexture() +{ + U8 bumpy = 0; + bool identical_bumpy = false; + LLSelectedTE::getBumpmap(bumpy, identical_bumpy); + LLUUID normal_map_id = mBumpyTextureCtrl->getImageAssetID(); + bumpy = normal_map_id.isNull() ? bumpy : BUMPY_TEXTURE; + sendBump(bumpy); +} + +void FSPanelFace::onCancelSpecularTexture() +{ + U8 shiny = 0; + bool identical_shiny = false; + LLSelectedTE::getShiny(shiny, identical_shiny); + LLUUID spec_map_id = mShinyTextureCtrl->getImageAssetID(); + shiny = spec_map_id.isNull() ? shiny : SHINY_TEXTURE; + sendShiny(shiny); +} + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to edit existing media settings on a prim or prim face +// TODO: test if there is media on the item and only allow editing if present +// NOTE: there is no actual "Button" Edit Media, but this function is called from +// onClickBtnAddMedia() where needed, so the naming is probably just old cruft -Zi +void FSPanelFace::onClickBtnEditMedia() +{ + refreshMedia(); + LLFloaterReg::showInstance("media_settings"); +} + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to delete media from a prim or prim face +void FSPanelFace::onClickBtnDeleteMedia() +{ + LLNotificationsUtil::add("DeleteMedia", LLSD(), LLSD(), boost::bind(&FSPanelFace::deleteMediaConfirm, this, _1, _2)); +} + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to add media to a prim or prim face +void FSPanelFace::onClickBtnAddMedia() +{ + // check if multiple faces are selected + if (LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected()) + { + refreshMedia(); + LLNotificationsUtil::add("MultipleFacesSelected", LLSD(), LLSD(), boost::bind(&FSPanelFace::multipleFacesSelectedConfirm, this, _1, _2)); + } + else + { + onClickBtnEditMedia(); + } +} + +bool FSPanelFace::deleteMediaConfirm(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch (option) + { + case 0: // "Yes" + LLSelectMgr::getInstance()->selectionSetMedia(0, LLSD()); + if (LLFloaterReg::instanceVisible("media_settings")) + { + LLFloaterReg::hideInstance("media_settings"); + } + break; + + case 1: // "No" + default: + break; + } + return false; +} + +bool FSPanelFace::multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch (option) + { + case 0: // "Yes" + LLFloaterReg::showInstance("media_settings"); + break; + + case 1: // "No" + default: + break; + } + return false; +} + +//static +void FSPanelFace::syncOffsetX(FSPanelFace* self, F32 offsetU) +{ + LLSelectedTEMaterial::setNormalOffsetX(self,offsetU); + LLSelectedTEMaterial::setSpecularOffsetX(self,offsetU); + self->mCtrlTexOffsetU->forceSetValue(offsetU); + self->sendTextureInfo(); +} + +//static +void FSPanelFace::syncOffsetY(FSPanelFace* self, F32 offsetV) +{ + LLSelectedTEMaterial::setNormalOffsetY(self,offsetV); + LLSelectedTEMaterial::setSpecularOffsetY(self,offsetV); + self->mCtrlTexOffsetV->forceSetValue(offsetV); + self->sendTextureInfo(); +} + +void FSPanelFace::onCommitMaterialBumpyOffsetX() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetX(this, getCurrentBumpyOffsetU()); + } + else + { + LLSelectedTEMaterial::setNormalOffsetX(this, getCurrentBumpyOffsetU()); + } +} + +void FSPanelFace::onCommitMaterialBumpyOffsetY() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetY(this, getCurrentBumpyOffsetV()); + } + else + { + LLSelectedTEMaterial::setNormalOffsetY(this, getCurrentBumpyOffsetV()); + } +} + +void FSPanelFace::onCommitMaterialShinyOffsetX() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetX(this, getCurrentShinyOffsetU()); + } + else + { + LLSelectedTEMaterial::setSpecularOffsetX(this, getCurrentShinyOffsetU()); + } +} + +void FSPanelFace::onCommitMaterialShinyOffsetY() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetY(this, getCurrentShinyOffsetV()); + } + else + { + LLSelectedTEMaterial::setSpecularOffsetY(this, getCurrentShinyOffsetV()); + } +} + +//static +void FSPanelFace::syncRepeatX(FSPanelFace* self, F32 scaleU) +{ + LLSelectedTEMaterial::setNormalRepeatX(self,scaleU); + LLSelectedTEMaterial::setSpecularRepeatX(self,scaleU); + self->sendTextureInfo(); +} + +//static +void FSPanelFace::syncRepeatY(FSPanelFace* self, F32 scaleV) +{ + LLSelectedTEMaterial::setNormalRepeatY(self,scaleV); + LLSelectedTEMaterial::setSpecularRepeatY(self,scaleV); + self->sendTextureInfo(); +} + +void FSPanelFace::onCommitMaterialBumpyScaleX() +{ + F32 bumpy_scale_u = getCurrentBumpyScaleU(); + if (isIdenticalPlanarTexgen()) + { + bumpy_scale_u *= 0.5f; + } + + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexScaleU->forceSetValue(getCurrentBumpyScaleU()); + syncRepeatX(this, bumpy_scale_u); + } + else + { + LLSelectedTEMaterial::setNormalRepeatX(this, bumpy_scale_u); + } +} + +void FSPanelFace::onCommitMaterialBumpyScaleY() +{ + F32 bumpy_scale_v = getCurrentBumpyScaleV(); + if (isIdenticalPlanarTexgen()) + { + bumpy_scale_v *= 0.5f; + } + + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexScaleV->forceSetValue(getCurrentBumpyScaleV()); + syncRepeatY(this, bumpy_scale_v); + } + else + { + LLSelectedTEMaterial::setNormalRepeatY(this, bumpy_scale_v); + } +} + +void FSPanelFace::onCommitMaterialShinyScaleX() +{ + F32 shiny_scale_u = getCurrentShinyScaleU(); + if (isIdenticalPlanarTexgen()) + { + shiny_scale_u *= 0.5f; + } + + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexScaleU->forceSetValue(getCurrentShinyScaleU()); + syncRepeatX(this, shiny_scale_u); + } + else + { + LLSelectedTEMaterial::setSpecularRepeatX(this, shiny_scale_u); + } +} + +void FSPanelFace::onCommitMaterialShinyScaleY() +{ + F32 shiny_scale_v = getCurrentShinyScaleV(); + if (isIdenticalPlanarTexgen()) + { + shiny_scale_v *= 0.5f; + } + + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexScaleV->forceSetValue(getCurrentShinyScaleV()); + syncRepeatY(this, shiny_scale_v); + } + else + { + LLSelectedTEMaterial::setSpecularRepeatY(this, shiny_scale_v); + } +} + +//static +void FSPanelFace::syncMaterialRot(FSPanelFace* self, F32 rot, int te) +{ + LLSelectedTEMaterial::setNormalRotation(self,rot * DEG_TO_RAD, te); + LLSelectedTEMaterial::setSpecularRotation(self,rot * DEG_TO_RAD, te); + self->sendTextureInfo(); +} + +void FSPanelFace::onCommitMaterialBumpyRot() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexRot->forceSetValue(getCurrentBumpyRot()); + syncMaterialRot(this, getCurrentBumpyRot()); + } + else + { + if (mCheckPlanarAlign->getValue().asBoolean()) + { + LLFace* last_face = NULL; + bool identical_face = false; + LLSelectedTE::getFace(last_face, identical_face); + FSPanelFaceSetAlignedTEFunctor setfunc(this, last_face); + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); + } + else + { + LLSelectedTEMaterial::setNormalRotation(this, getCurrentBumpyRot() * DEG_TO_RAD); + } + } +} + +void FSPanelFace::onCommitMaterialShinyRot() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexRot->forceSetValue(getCurrentShinyRot()); + syncMaterialRot(this, getCurrentShinyRot()); + } + else + { + if (mCheckPlanarAlign->getValue().asBoolean()) + { + LLFace* last_face = NULL; + bool identical_face = false; + LLSelectedTE::getFace(last_face, identical_face); + FSPanelFaceSetAlignedTEFunctor setfunc(this, last_face); + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); + } + else + { + LLSelectedTEMaterial::setSpecularRotation(this, getCurrentShinyRot() * DEG_TO_RAD); + } + } +} + +void FSPanelFace::onCommitMaterialGloss() +{ + LLSelectedTEMaterial::setSpecularLightExponent(this, getCurrentGlossiness()); +} + +void FSPanelFace::onCommitMaterialEnv() +{ + LLSelectedTEMaterial::setEnvironmentIntensity(this, getCurrentEnvIntensity()); +} + +void FSPanelFace::onCommitMaterialMaskCutoff() +{ + LLSelectedTEMaterial::setAlphaMaskCutoff(this, getCurrentAlphaMaskCutoff()); +} + +void FSPanelFace::onCommitTextureScaleX() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + F32 bumpy_scale_u = mCtrlTexScaleU->getValue().asReal(); + if (isIdenticalPlanarTexgen()) + { + bumpy_scale_u *= 0.5f; + } + syncRepeatX(this, bumpy_scale_u); + } + else + { + sendTextureInfo(); + } + updateUI(true); +} + +void FSPanelFace::onCommitTextureScaleY() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + F32 bumpy_scale_v = mCtrlTexScaleV->getValue().asReal(); + if (isIdenticalPlanarTexgen()) + { + bumpy_scale_v *= 0.5f; + } + syncRepeatY(this, bumpy_scale_v); + } + else + { + sendTextureInfo(); + } + updateUI(true); +} + +void FSPanelFace::onCommitTextureRot() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncMaterialRot(this, mCtrlTexRot->getValue().asReal()); + } + else + { + sendTextureInfo(); + } + updateUI(true); +} + + +void FSPanelFace::onCommitTextureOffsetX() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetX(this, mCtrlTexOffsetU->getValue().asReal()); + } + else + { + sendTextureInfo(); + } + updateUI(true); +} + +void FSPanelFace::onCommitTextureOffsetY() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetY(this, mCtrlTexOffsetV->getValue().asReal()); + } + else + { + sendTextureInfo(); + } + updateUI(true); +} + +// Commit the number of repeats per meter +void FSPanelFace::onCommitRepeatsPerMeter() +{ + S32 materials_media = getCurrentMaterialType(); + S32 material_type = 0; + // TODO: check if repeats per meter is even used for PBR -Zi + if (materials_media == MATMEDIA_PBR) + { + material_type = getCurrentPBRChannel(); + } + + if (materials_media == MATMEDIA_MATERIAL) + { + material_type = getCurrentMatChannel(); + } + + F32 repeats_per_meter = mCtrlRpt->getValue().asReal(); + + F32 obj_scale_s = 1.0f; + F32 obj_scale_t = 1.0f; + + bool identical_scale_s = false; + bool identical_scale_t = false; + + LLSelectedTE::getObjectScaleS(obj_scale_s, identical_scale_s); + LLSelectedTE::getObjectScaleS(obj_scale_t, identical_scale_t); + + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + LLSelectMgr::getInstance()->selectionTexScaleAutofit(repeats_per_meter); + + mCtrlBumpyScaleU->setValue(obj_scale_s * repeats_per_meter); + mCtrlBumpyScaleV->setValue(obj_scale_t * repeats_per_meter); + + LLSelectedTEMaterial::setNormalRepeatX(this, obj_scale_s * repeats_per_meter); + LLSelectedTEMaterial::setNormalRepeatY(this, obj_scale_t * repeats_per_meter); + + mCtrlShinyScaleU->setValue(obj_scale_s * repeats_per_meter); + mCtrlShinyScaleV->setValue(obj_scale_t * repeats_per_meter); + + LLSelectedTEMaterial::setSpecularRepeatX(this, obj_scale_s * repeats_per_meter); + LLSelectedTEMaterial::setSpecularRepeatY(this, obj_scale_t * repeats_per_meter); + } + else + { + switch (material_type) + { + case MATTYPE_DIFFUSE: + { + LLSelectMgr::getInstance()->selectionTexScaleAutofit(repeats_per_meter); + } + break; + + case MATTYPE_NORMAL: + { + mCtrlBumpyScaleU->setValue(obj_scale_s * repeats_per_meter); + mCtrlBumpyScaleV->setValue(obj_scale_t * repeats_per_meter); + + LLSelectedTEMaterial::setNormalRepeatX(this, obj_scale_s * repeats_per_meter); + LLSelectedTEMaterial::setNormalRepeatY(this, obj_scale_t * repeats_per_meter); + } + break; + + case MATTYPE_SPECULAR: + { + mCtrlShinyScaleU->setValue(obj_scale_s * repeats_per_meter); + mCtrlShinyScaleV->setValue(obj_scale_t * repeats_per_meter); + + LLSelectedTEMaterial::setSpecularRepeatX(this, obj_scale_s * repeats_per_meter); + LLSelectedTEMaterial::setSpecularRepeatY(this, obj_scale_t * repeats_per_meter); + } + break; + + default: + llassert(false); + break; + } + } + + // vertical scale and repeats per meter depends on each other, so force set on changes + updateUI(true); +} + +struct FSPanelFaceSetMediaFunctor : public LLSelectedTEFunctor +{ + virtual bool apply(LLViewerObject* object, S32 te) + { + viewer_media_t pMediaImpl; + + const LLTextureEntry &tep = object->getTEref(te); + const LLMediaEntry* mep = tep.hasMedia() ? tep.getMediaData() : NULL; + if (mep) + { + pMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); + } + + if (pMediaImpl.isNull()) + { + // If we didn't find face media for this face, check whether this face is showing parcel media. + pMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep.getID()); + } + + if (pMediaImpl.notNull()) + { + LLPluginClassMedia *media = pMediaImpl->getMediaPlugin(); + if(media) + { + S32 media_width = media->getWidth(); + S32 media_height = media->getHeight(); + S32 texture_width = media->getTextureWidth(); + S32 texture_height = media->getTextureHeight(); + F32 scale_s = (F32)media_width / (F32)texture_width; + F32 scale_t = (F32)media_height / (F32)texture_height; + + // set scale and adjust offset + object->setTEScaleS( te, scale_s ); + object->setTEScaleT( te, scale_t ); // don't need to flip Y anymore since QT does this for us now. + object->setTEOffsetS( te, -( 1.0f - scale_s ) / 2.0f ); + object->setTEOffsetT( te, -( 1.0f - scale_t ) / 2.0f ); + } + } + return true; + }; +}; + +void FSPanelFace::onClickAutoFix() +{ + FSPanelFaceSetMediaFunctor setfunc; + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); + + FSPanelFaceSendFunctor sendfunc; + LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc); +} + +void FSPanelFace::onAlignTexture() +{ + alignTextureLayer(); +} + +void FSPanelFace::onClickBtnSavePBR() +{ + LLMaterialEditor::saveObjectsMaterialAs(); +} + +enum EPasteMode +{ + PASTE_COLOR, + PASTE_TEXTURE +}; + +struct FSPanelFacePasteTexFunctor : public LLSelectedTEFunctor +{ + public: + FSPanelFacePasteTexFunctor(FSPanelFace* panel, EPasteMode mode) : + mPanelFace(panel), + mMode(mode) + { + } + + virtual bool apply(LLViewerObject* objectp, S32 te) + { + switch(mMode) + { + case PASTE_COLOR: + mPanelFace->onPasteColor(objectp, te); + break; + + case PASTE_TEXTURE: + mPanelFace->onPasteTexture(objectp, te); + break; + } + return true; + } + + private: + FSPanelFace *mPanelFace; + EPasteMode mMode; +}; + +struct FSPanelFaceUpdateFunctor : public LLSelectedObjectFunctor +{ + public: + FSPanelFaceUpdateFunctor(bool update_media) : + mUpdateMedia(update_media) + { + } + + virtual bool apply(LLViewerObject* object) + { + object->sendTEUpdate(); + + if (mUpdateMedia) + { + LLVOVolume *vo = dynamic_cast(object); + if (vo && vo->hasMedia()) + { + vo->sendMediaDataUpdate(); + } + } + return true; + } + + private: + bool mUpdateMedia; +}; + +struct FSPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor +{ + virtual bool apply(LLViewerObject* objectp, S32 te) + { + if (objectp && objectp->getTE(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + const LLMediaEntry *media_data = tep->getMediaData(); + if (media_data) + { + if (media_data->getCurrentURL().empty() && media_data->getAutoPlay()) + { + viewer_media_t media_impl = + LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getMediaData()->getMediaID()); + if (media_impl) + { + media_impl->navigateHome(); + } + } + } + } + return true; + } +}; + +void FSPanelFace::onCopyColor() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + return; + } + + if (mClipboardParams.has("color")) + { + mClipboardParams["color"].clear(); + } + else + { + mClipboardParams["color"] = LLSD::emptyArray(); + } + + std::map asset_item_map; + + // a way to resolve situations where source and target have different amount of faces + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + mClipboardParams["color_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()); + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + LLSD te_data; + + // asLLSD() includes media + te_data["te"] = tep->asLLSD(); // Note: includes a lot more than just color/alpha/glow + + mClipboardParams["color"].append(te_data); + } + } + } +} + +void FSPanelFace::onPasteColor() +{ + if (!mClipboardParams.has("color")) + { + return; + } + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + // not supposed to happen + LL_WARNS() << "Failed to paste color due to missing or wrong selection" << LL_ENDL; + return; + } + + bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); + LLSD &clipboard = mClipboardParams["color"]; // array + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + S32 compare_tes = num_tes; + + if (face_selection_mode) + { + compare_tes = 0; + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + compare_tes++; + } + } + } + + // we can copy if single face was copied in edit face mode or if face count matches + if (!((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean()) + && compare_tes != clipboard.size()) + { + LLSD notif_args; + if (face_selection_mode) + { + static std::string reason = getString("paste_error_face_selection_mismatch"); + notif_args["REASON"] = reason; + } + else + { + static std::string reason = getString("paste_error_object_face_count_mismatch"); + notif_args["REASON"] = reason; + } + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + FSPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR); + selected_objects->applyToTEs(&paste_func); + + FSPanelFaceUpdateFunctor sendfunc(false); + selected_objects->applyToObjects(&sendfunc); +} + +void FSPanelFace::onPasteColor(LLViewerObject* objectp, S32 te) +{ + LLSD te_data; + LLSD &clipboard = mClipboardParams["color"]; // array + if ((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean()) + { + te_data = *(clipboard.beginArray()); + } + else if (clipboard[te]) + { + te_data = clipboard[te]; + } + else + { + return; + } + + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + if (te_data.has("te")) + { + // Color / Alpha + if (te_data["te"].has("colors")) + { + LLColor4 color = tep->getColor(); + + LLColor4 clip_color; + clip_color.setValue(te_data["te"]["colors"]); + + // Color + color.mV[VRED] = clip_color.mV[VRED]; + color.mV[VGREEN] = clip_color.mV[VGREEN]; + color.mV[VBLUE] = clip_color.mV[VBLUE]; + + // Alpha + color.mV[VALPHA] = clip_color.mV[VALPHA]; + + objectp->setTEColor(te, color); + } + + // Color/fullbright + if (te_data["te"].has("fullbright")) + { + objectp->setTEFullbright(te, te_data["te"]["fullbright"].asInteger()); + } + + // Glow + if (te_data["te"].has("glow")) + { + objectp->setTEGlow(te, (F32)te_data["te"]["glow"].asReal()); + } + } + } +} + +void FSPanelFace::onCopyTexture() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1 + || !LLMaterialEditor::canClipboardObjectsMaterial()) + { + return; + } + + if (mClipboardParams.has("texture")) + { + mClipboardParams["texture"].clear(); + } + else + { + mClipboardParams["texture"] = LLSD::emptyArray(); + } + + std::map asset_item_map; + + // a way to resolve situations where source and target have different amount of faces + S32 num_tes = llmin((S32)objectp->getNumTEs(), objectp->getNumFaces()); + mClipboardParams["texture_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()); + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + LLSD te_data; + + // asLLSD() includes media + te_data["te"] = tep->asLLSD(); + te_data["te"]["shiny"] = tep->getShiny(); + te_data["te"]["bumpmap"] = tep->getBumpmap(); + te_data["te"]["bumpshiny"] = tep->getBumpShiny(); + te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright(); + te_data["te"]["texgen"] = tep->getTexGen(); + te_data["te"]["pbr"] = objectp->getRenderMaterialID(te); + if (tep->getGLTFMaterialOverride() != nullptr) + { + te_data["te"]["pbr_override"] = tep->getGLTFMaterialOverride()->asJSON(); + } + + if (te_data["te"].has("imageid")) + { + LLUUID item_id; + LLUUID id = te_data["te"]["imageid"].asUUID(); + bool from_library = get_is_predefined_texture(id); + bool full_perm = from_library; + + if (!full_perm + && objectp->permCopy() + && objectp->permTransfer() + && objectp->permModify()) + { + // If agent created this object and nothing is limiting permissions, mark as full perm + // If agent was granted permission to edit objects owned and created by somebody else, mark full perm + // This check is not perfect since we can't figure out whom textures belong to so this ended up restrictive + std::string creator_app_link; + LLUUID creator_id; + LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_app_link); + full_perm = objectp->mOwnerID == creator_id; + } + + if (id.notNull() && !full_perm) + { + std::map::iterator iter = asset_item_map.find(id); + if (iter != asset_item_map.end()) + { + item_id = iter->second; + } + else + { + // What this does is simply searches inventory for item with same asset id, + // as result it is highly unreliable, leaves little control to user, borderline hack + // but there are little options to preserve permissions - multiple inventory + // items might reference same asset and inventory search is expensive. + bool no_transfer = false; + if (objectp->getInventoryItemByAsset(id)) + { + no_transfer = !objectp->getInventoryItemByAsset(id)->getIsFullPerm(); + } + item_id = get_copy_free_item_by_asset_id(id, no_transfer); + // record value to avoid repeating inventory search when possible + asset_item_map[id] = item_id; + } + } + + if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID())) + { + full_perm = true; + from_library = true; + } + + // TODO: why scope this? -Zi + { + te_data["te"]["itemfullperm"] = full_perm; + te_data["te"]["fromlibrary"] = from_library; + + // If full permission object, texture is free to copy, + // but otherwise we need to check inventory and extract permissions + // + // Normally we care only about restrictions for current user and objects + // don't inherit any 'next owner' permissions from texture, so there is + // no need to record item id if full_perm==true + if (!full_perm && !from_library && item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (itemp) + { + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + te_data["te"]["imageitemid"] = item_id; + te_data["te"]["itemfullperm"] = itemp->getIsFullPerm(); + if (!itemp->isFinished()) + { + // needed for dropTextureAllFaces + LLInventoryModelBackgroundFetch::instance().start(item_id, false); + } + } + } + } + } + } + + LLMaterialPtr material_ptr = tep->getMaterialParams(); + if (!material_ptr.isNull()) + { + LLSD mat_data; + + mat_data["NormMap"] = material_ptr->getNormalID(); + mat_data["SpecMap"] = material_ptr->getSpecularID(); + + mat_data["NormRepX"] = material_ptr->getNormalRepeatX(); + mat_data["NormRepY"] = material_ptr->getNormalRepeatY(); + mat_data["NormOffX"] = material_ptr->getNormalOffsetX(); + mat_data["NormOffY"] = material_ptr->getNormalOffsetY(); + mat_data["NormRot"] = material_ptr->getNormalRotation(); + + mat_data["SpecRepX"] = material_ptr->getSpecularRepeatX(); + mat_data["SpecRepY"] = material_ptr->getSpecularRepeatY(); + mat_data["SpecOffX"] = material_ptr->getSpecularOffsetX(); + mat_data["SpecOffY"] = material_ptr->getSpecularOffsetY(); + mat_data["SpecRot"] = material_ptr->getSpecularRotation(); + + mat_data["SpecColor"] = material_ptr->getSpecularLightColor().getValue(); + mat_data["SpecExp"] = material_ptr->getSpecularLightExponent(); + mat_data["EnvIntensity"] = material_ptr->getEnvironmentIntensity(); + mat_data["AlphaMaskCutoff"] = material_ptr->getAlphaMaskCutoff(); + mat_data["DiffuseAlphaMode"] = material_ptr->getDiffuseAlphaMode(); + + // Replace no-copy textures, destination texture will get used instead if available + if (mat_data.has("NormMap")) + { + LLUUID id = mat_data["NormMap"].asUUID(); + if (id.notNull() && !get_can_copy_texture(id)) + { + mat_data["NormMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + mat_data["NormMapNoCopy"] = true; + } + } + if (mat_data.has("SpecMap")) + { + LLUUID id = mat_data["SpecMap"].asUUID(); + if (id.notNull() && !get_can_copy_texture(id)) + { + mat_data["SpecMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + mat_data["SpecMapNoCopy"] = true; + } + } + + te_data["material"] = mat_data; + } + + mClipboardParams["texture"].append(te_data); + } + } + } +} + +void FSPanelFace::onPasteTexture() +{ + if (!mClipboardParams.has("texture")) + { + return; + } + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1 + || !LLMaterialEditor::canClipboardObjectsMaterial()) + { + // not supposed to happen + LL_WARNS() << "Failed to paste texture due to missing or wrong selection" << LL_ENDL; + return; + } + + bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); + LLSD &clipboard = mClipboardParams["texture"]; // array + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + S32 compare_tes = num_tes; + + if (face_selection_mode) + { + compare_tes = 0; + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + compare_tes++; + } + } + } + + // we can copy if single face was copied in edit face mode or if face count matches + if (!((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) + && compare_tes != clipboard.size()) + { + LLSD notif_args; + if (face_selection_mode) + { + static std::string reason = getString("paste_error_face_selection_mismatch"); + notif_args["REASON"] = reason; + } + else + { + static std::string reason = getString("paste_error_object_face_count_mismatch"); + notif_args["REASON"] = reason; + } + + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + + bool full_perm_object = true; + + LLSD::array_const_iterator iter = clipboard.beginArray(); + LLSD::array_const_iterator end = clipboard.endArray(); + + for (; iter != end; ++iter) + { + const LLSD& te_data = *iter; + if (te_data.has("te") && te_data["te"].has("imageid")) + { + bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); + full_perm_object &= full_perm; + if (!full_perm) + { + if (te_data["te"].has("imageitemid")) + { + LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); + if (item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (!itemp) + { + // image might be in object's inventory, but it can be not up to date + LLSD notif_args; + static std::string reason = getString("paste_error_inventory_not_found"); + notif_args["REASON"] = reason; + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + } + } + else + { + // Item was not found on 'copy' stage + // Since this happened at copy, might be better to either show this + // at copy stage or to drop clipboard here + LLSD notif_args; + static std::string reason = getString("paste_error_inventory_not_found"); + notif_args["REASON"] = reason; + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + } + } + } + + if (!full_perm_object) + { + LLNotificationsUtil::add("FacePasteTexturePermissions"); + } + + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + FSPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE); + selected_objects->applyToTEs(&paste_func); + + FSPanelFaceUpdateFunctor sendfunc(true); + selected_objects->applyToObjects(&sendfunc); + + LLGLTFMaterialList::flushUpdates(); + + FSPanelFaceNavigateHomeFunctor navigate_home_func; + selected_objects->applyToTEs(&navigate_home_func); +} + +void FSPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) +{ + LLSD te_data; + LLSD &clipboard = mClipboardParams["texture"]; // array + if ((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) + { + te_data = *(clipboard.beginArray()); + } + else if (clipboard[te]) + { + te_data = clipboard[te]; + } + else + { + return; + } + + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + if (te_data.has("te")) + { + // Texture + bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); + bool from_library = te_data["te"].has("fromlibrary") && te_data["te"]["fromlibrary"].asBoolean(); + if (te_data["te"].has("imageid")) + { + const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id + LLViewerInventoryItem* itemp_res = NULL; + + if (te_data["te"].has("imageitemid")) + { + LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); + if (item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (itemp && itemp->isFinished()) + { + // dropTextureAllFaces will fail if incomplete + itemp_res = itemp; + } + else + { + // Theoretically shouldn't happen, but if it does happen, we + // might need to add a notification to user that paste will fail + // since inventory isn't fully loaded + LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL; + } + } + } + // for case when item got removed from inventory after we pressed 'copy' + // or texture got pasted into previous object + if (!itemp_res && !full_perm) + { + // Due to checks for imageitemid in FSPanelFace::onPasteTexture() this should no longer be reachable. + LL_INFOS() << "Item " << te_data["te"]["imageitemid"].asUUID() << " no longer in inventory." << LL_ENDL; + // Todo: fix this, we are often searching same texture multiple times (equal to number of faces) + // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(imageid); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + // Extremely unreliable and performance unfriendly. + // But we need this to check permissions and it is how texture control finds items + for (S32 i = 0; i < items.size(); i++) + { + LLViewerInventoryItem* itemp = items[i]; + if (itemp && itemp->isFinished()) + { + // dropTextureAllFaces will fail if incomplete + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + itemp_res = itemp; + break; // first match + } + } + } + } + + if (itemp_res) + { + if (te == -1) // all faces + { + LLToolDragAndDrop::dropTextureAllFaces(objectp, + itemp_res, + from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, + LLUUID::null, + false); + } + else // one face + { + LLToolDragAndDrop::dropTextureOneFace(objectp, + te, + itemp_res, + from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, + LLUUID::null, + false, + 0); + } + } + // not an inventory item or no complete items + else if (full_perm) + { + // Either library, local or existed as fullperm when user made a copy + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + objectp->setTEImage(U8(te), image); + } + } + + if (te_data["te"].has("bumpmap")) + { + objectp->setTEBumpmap(te, (U8)te_data["te"]["bumpmap"].asInteger()); + } + if (te_data["te"].has("bumpshiny")) + { + objectp->setTEBumpShiny(te, (U8)te_data["te"]["bumpshiny"].asInteger()); + } + if (te_data["te"].has("bumpfullbright")) + { + objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger()); + } + if (te_data["te"].has("texgen")) + { + objectp->setTETexGen(te, (U8)te_data["te"]["texgen"].asInteger()); + } + + // PBR/GLTF + if (te_data["te"].has("pbr")) + { + objectp->setRenderMaterialID(te, te_data["te"]["pbr"].asUUID(), false /*managing our own update*/); + tep->setGLTFRenderMaterial(nullptr); + tep->setGLTFMaterialOverride(nullptr); + + LLSD override_data; + override_data["object_id"] = objectp->getID(); + override_data["side"] = te; + if (te_data["te"].has("pbr_override")) + { + override_data["gltf_json"] = te_data["te"]["pbr_override"]; + } + else + { + override_data["gltf_json"] = ""; + } + + override_data["asset_id"] = te_data["te"]["pbr"].asUUID(); + + LLGLTFMaterialList::queueUpdate(override_data); + } + else + { + objectp->setRenderMaterialID(te, LLUUID::null, false /*send in bulk later*/ ); + tep->setGLTFRenderMaterial(nullptr); + tep->setGLTFMaterialOverride(nullptr); + + // blank out most override data on the server + LLGLTFMaterialList::queueApply(objectp, te, LLUUID::null); + } + + // Texture map + if (te_data["te"].has("scales") && te_data["te"].has("scalet")) + { + objectp->setTEScale(te, (F32)te_data["te"]["scales"].asReal(), (F32)te_data["te"]["scalet"].asReal()); + } + if (te_data["te"].has("offsets") && te_data["te"].has("offsett")) + { + objectp->setTEOffset(te, (F32)te_data["te"]["offsets"].asReal(), (F32)te_data["te"]["offsett"].asReal()); + } + if (te_data["te"].has("imagerot")) + { + objectp->setTERotation(te, (F32)te_data["te"]["imagerot"].asReal()); + } + + // Media + if (te_data["te"].has("media_flags")) + { + U8 media_flags = te_data["te"]["media_flags"].asInteger(); + objectp->setTEMediaFlags(te, media_flags); + LLVOVolume *vo = dynamic_cast(objectp); + if (vo && te_data["te"].has(LLTextureEntry::TEXTURE_MEDIA_DATA_KEY)) + { + vo->syncMediaData(te, te_data["te"][LLTextureEntry::TEXTURE_MEDIA_DATA_KEY], true/*merge*/, true/*ignore_agent*/); + } + } + else + { + // Keep media flags on destination unchanged + } + } + + if (te_data.has("material")) + { + LLUUID object_id = objectp->getID(); + + // Normal + // Replace placeholders with target's + if (te_data["material"].has("NormMapNoCopy")) + { + LLMaterialPtr material = tep->getMaterialParams(); + if (material.notNull()) + { + LLUUID id = material->getNormalID(); + if (id.notNull()) + { + te_data["material"]["NormMap"] = id; + } + } + } + + LLSelectedTEMaterial::setNormalID(this, te_data["material"]["NormMap"].asUUID(), te, object_id); + LLSelectedTEMaterial::setNormalRepeatX(this, (F32)te_data["material"]["NormRepX"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalRepeatY(this, (F32)te_data["material"]["NormRepY"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalOffsetX(this, (F32)te_data["material"]["NormOffX"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalOffsetY(this, (F32)te_data["material"]["NormOffY"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalRotation(this, (F32)te_data["material"]["NormRot"].asReal(), te, object_id); + + // Specular + // Replace placeholders with target's + if (te_data["material"].has("SpecMapNoCopy")) + { + LLMaterialPtr material = tep->getMaterialParams(); + if (material.notNull()) + { + LLUUID id = material->getSpecularID(); + if (id.notNull()) + { + te_data["material"]["SpecMap"] = id; + } + } + } + + LLSelectedTEMaterial::setSpecularID(this, te_data["material"]["SpecMap"].asUUID(), te, object_id); + LLSelectedTEMaterial::setSpecularRepeatX(this, (F32)te_data["material"]["SpecRepX"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularRepeatY(this, (F32)te_data["material"]["SpecRepY"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularOffsetX(this, (F32)te_data["material"]["SpecOffX"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularOffsetY(this, (F32)te_data["material"]["SpecOffY"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularRotation(this, (F32)te_data["material"]["SpecRot"].asReal(), te, object_id); + LLColor4U spec_color(te_data["material"]["SpecColor"]); + LLSelectedTEMaterial::setSpecularLightColor(this, spec_color, te); + LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id); + LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id); + LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["DiffuseAlphaMode"].asInteger(), te, object_id); + LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["AlphaMaskCutoff"].asInteger(), te, object_id); + + if (te_data.has("te") && te_data["te"].has("shiny")) + { + objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger()); + } + } + } +} + +void FSPanelFace::onCopyFaces() +{ + onCopyTexture(); + onCopyColor(); + mBtnPasteFaces->setEnabled(!mClipboardParams.emptyMap() && (mClipboardParams.has("color") || mClipboardParams.has("texture"))); +} + +void FSPanelFace::onPasteFaces() +{ + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + FSPanelFacePasteTexFunctor paste_texture_func(this, PASTE_TEXTURE); + selected_objects->applyToTEs(&paste_texture_func); + + FSPanelFacePasteTexFunctor paste_color_func(this, PASTE_COLOR); + selected_objects->applyToTEs(&paste_color_func); + + FSPanelFaceUpdateFunctor sendfunc(true); + selected_objects->applyToObjects(&sendfunc); + + FSPanelFaceNavigateHomeFunctor navigate_home_func; + selected_objects->applyToTEs(&navigate_home_func); +} + +void FSPanelFace::onCommitPlanarAlign() +{ + getState(); + sendTextureInfo(); +} + +void FSPanelFace::updateGLTFTextureTransform(float value, U32 pbr_channel, std::function edit) +{ + U32 texture_info_start; + U32 texture_info_end; + + const LLGLTFMaterial::TextureInfo texture_info = mPBRChannelToTextureInfo[pbr_channel]; + if (texture_info == LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT) + { + texture_info_start = 0; + texture_info_end = LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; + } + else + { + texture_info_start = mPBRChannelToTextureInfo[pbr_channel]; + texture_info_end = texture_info_start + 1; + } + + updateSelectedGLTFMaterials([&](LLGLTFMaterial* new_override) + { + for (U32 ti = texture_info_start; ti < texture_info_end; ++ti) + { + LLGLTFMaterial::TextureTransform& new_transform = new_override->mTextureTransform[(LLGLTFMaterial::TextureInfo)ti]; + edit(&new_transform); + } + }); +} + +void FSPanelFace::setMaterialOverridesFromSelection() +{ + // TODO: move to .h -Zi + std::map spinner_suffixes = + { + { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_BASE_COLOR, "_Base" }, + { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_NORMAL, "_Normal" }, + { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, "_Metallic" }, + { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_EMISSIVE, "_Emissive" } + }; + + bool read_transform = true; + LLGLTFMaterial::TextureTransform transform; + bool scale_u_same = true; + bool scale_v_same = true; + bool rotation_same = true; + bool offset_u_same = true; + bool offset_v_same = true; + + // Always iterate over the whole set of texture channels + for (U32 i = 0; i < LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_COUNT; ++i) + { + std::string spinner_suffix = spinner_suffixes[(LLGLTFMaterial::TextureInfo) i]; + + LLGLTFMaterial::TextureTransform this_transform; + + bool this_scale_u_same = true; + bool this_scale_v_same = true; + bool this_rotation_same = true; + bool this_offset_u_same = true; + bool this_offset_v_same = true; + + readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[i].mScale[VX] : 0.f; + }, this_transform.mScale[VX], this_scale_u_same, true, 1e-3f); + + readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[i].mScale[VY] : 0.f; + }, this_transform.mScale[VY], this_scale_v_same, true, 1e-3f); + + readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[i].mRotation : 0.f; + }, this_transform.mRotation, this_rotation_same, true, 1e-3f); + + readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[i].mOffset[VX] : 0.f; + }, this_transform.mOffset[VX], this_offset_u_same, true, 1e-3f); + + readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[i].mOffset[VY] : 0.f; + }, this_transform.mOffset[VY], this_offset_v_same, true, 1e-3f); + + scale_u_same = scale_u_same && this_scale_u_same; + scale_v_same = scale_v_same && this_scale_v_same; + rotation_same = rotation_same && this_rotation_same; + offset_u_same = offset_u_same && this_offset_u_same; + offset_v_same = offset_v_same && this_offset_v_same; + + if (read_transform) + { + read_transform = false; + transform = this_transform; + } + else + { + scale_u_same = scale_u_same && (this_transform.mScale[VX] == transform.mScale[VX]); + scale_v_same = scale_v_same && (this_transform.mScale[VY] == transform.mScale[VY]); + rotation_same = rotation_same && (this_transform.mRotation == transform.mRotation); + offset_u_same = offset_u_same && (this_transform.mOffset[VX] == transform.mOffset[VX]); + offset_v_same = offset_v_same && (this_transform.mOffset[VY] == transform.mOffset[VY]); + } + + LLUICtrl* gltfCtrlTextureScaleU = findChild("gltfTextureScaleU" + spinner_suffix); + LLUICtrl* gltfCtrlTextureScaleV = findChild("gltfTextureScaleV" + spinner_suffix); + LLUICtrl* gltfCtrlTextureRotation = findChild("gltfTextureRotation" + spinner_suffix); + LLUICtrl* gltfCtrlTextureOffsetU = findChild("gltfTextureOffsetU" + spinner_suffix); + LLUICtrl* gltfCtrlTextureOffsetV = findChild("gltfTextureOffsetV" + spinner_suffix); + + gltfCtrlTextureScaleU->setValue(this_transform.mScale[VX]); + gltfCtrlTextureScaleV->setValue(this_transform.mScale[VY]); + gltfCtrlTextureRotation->setValue(this_transform.mRotation * RAD_TO_DEG); + gltfCtrlTextureOffsetU->setValue(this_transform.mOffset[VX]); + gltfCtrlTextureOffsetV->setValue(this_transform.mOffset[VY]); + } + + LLUICtrl* gltfCtrlTextureScaleU = findChild("gltfTextureScaleU_All"); + LLUICtrl* gltfCtrlTextureScaleV = findChild("gltfTextureScaleV_All"); + LLUICtrl* gltfCtrlTextureRotation = findChild("gltfTextureRotation_All"); + LLUICtrl* gltfCtrlTextureOffsetU = findChild("gltfTextureOffsetU_All"); + LLUICtrl* gltfCtrlTextureOffsetV = findChild("gltfTextureOffsetV_All"); + + gltfCtrlTextureScaleU->setValue(transform.mScale[VX]); + gltfCtrlTextureScaleV->setValue(transform.mScale[VY]); + gltfCtrlTextureRotation->setValue(transform.mRotation * RAD_TO_DEG); + gltfCtrlTextureOffsetU->setValue(transform.mOffset[VX]); + gltfCtrlTextureOffsetV->setValue(transform.mOffset[VY]); + + gltfCtrlTextureScaleU->setTentative(!scale_u_same); + gltfCtrlTextureScaleV->setTentative(!scale_v_same); + gltfCtrlTextureRotation->setTentative(!rotation_same); + gltfCtrlTextureOffsetU->setTentative(!offset_u_same); + gltfCtrlTextureOffsetV->setTentative(!offset_v_same); +} + +void FSPanelFace::Selection::connect() +{ + if (!mSelectConnection.connected()) + { + mSelectConnection = LLSelectMgr::instance().mUpdateSignal.connect(boost::bind(&FSPanelFace::Selection::onSelectionChanged, this)); + } +} + +bool FSPanelFace::Selection::update() +{ + const bool changed = mChanged || compareSelection(); + mChanged = false; + return changed; +} + +void FSPanelFace::Selection::onSelectedObjectUpdated(const LLUUID& object_id, S32 side) +{ + if (object_id == mSelectedObjectID) + { + if (side == mLastSelectedSide) + { + mChanged = true; + } + else if (mLastSelectedSide == -1) // if last selected face was deselected + { + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + if (node && node->isTESelected(side)) + { + mChanged = true; + } + } + } +} + +bool FSPanelFace::Selection::compareSelection() +{ + if (!mNeedsSelectionCheck) + { + return false; + } + + mNeedsSelectionCheck = false; + + const S32 old_object_count = mSelectedObjectCount; + const S32 old_te_count = mSelectedTECount; + const LLUUID old_object_id = mSelectedObjectID; + const S32 old_side = mLastSelectedSide; + + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLSelectNode* node = selection->getFirstNode(); + if (node) + { + LLViewerObject* object = node->getObject(); + mSelectedObjectCount = selection->getObjectCount(); + mSelectedTECount = selection->getTECount(); + mSelectedObjectID = object->getID(); + mLastSelectedSide = node->getLastSelectedTE(); + } + else + { + mSelectedObjectCount = 0; + mSelectedTECount = 0; + mSelectedObjectID = LLUUID::null; + mLastSelectedSide = -1; + } + + const bool selection_changed = + old_object_count != mSelectedObjectCount + || old_te_count != mSelectedTECount + || old_object_id != mSelectedObjectID + || old_side != mLastSelectedSide; + + mChanged = mChanged || selection_changed; + + return selection_changed; +} + +void FSPanelFace::onCommitGLTFUVSpinner(const LLUICtrl* ctrl, const LLSD& user_data) +{ + // TODO: put into .h -Zi + std::map types = + { + { "all", PBRTYPE_RENDER_MATERIAL_ID }, + { "base", PBRTYPE_BASE_COLOR }, + { "normal", PBRTYPE_NORMAL }, + { "metallic", PBRTYPE_METALLIC_ROUGHNESS }, + { "emissive", PBRTYPE_EMISSIVE } + }; + + std::string user_data_string = user_data.asString(); + + if (!types.count(user_data_string)) + { + LL_WARNS() << "Unknown PBR channel " << user_data_string << LL_ENDL; + return; + } + + const S32 pbr_channel = types[user_data.asString()]; + + const std::string& spinner_name = ctrl->getName(); + const float value = ctrl->getValue().asReal(); + + if (LLStringUtil::startsWith(spinner_name, "gltfTextureScaleU")) + { + updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform) + { + new_transform->mScale.mV[VX] = value; + }); + } + else if (LLStringUtil::startsWith(spinner_name, "gltfTextureScaleV")) + { + updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform) + { + new_transform->mScale.mV[VY] = value; + }); + } + else if (LLStringUtil::startsWith(spinner_name, "gltfTextureRotation")) + { + updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform) + { + new_transform->mRotation = value * DEG_TO_RAD; + }); + } + else if (LLStringUtil::startsWith(spinner_name, "gltfTextureOffsetU")) + { + updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform) + { + new_transform->mOffset.mV[VX] = value; + }); + } + else if (LLStringUtil::startsWith(spinner_name, "gltfTextureOffsetV")) + { + updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform) + { + new_transform->mOffset.mV[VY] = value; + }); + } +} + +// selection inside the texture/material picker changed +void FSPanelFace::onTextureSelectionChanged(const std::string& which_control) +{ + LL_DEBUGS("Materials") << "control " << which_control << LL_ENDL; + + LLTextureCtrl* texture_ctrl = findChild(which_control); + if (texture_ctrl) + { + LLInventoryItem* itemp = gInventory.getItem(texture_ctrl->getImageItemID()); + if (!itemp) + { + // no inventory asset available, i.e. could be "Blank" + return; + } + + LL_WARNS("Materials") << "item inventory id " << itemp->getUUID() << " - item asset " << itemp->getAssetUUID() << LL_ENDL; + + LLUUID obj_owner_id; + std::string obj_owner_name; + LLSelectMgr::instance().selectGetOwner(obj_owner_id, obj_owner_name); + + LLSaleInfo sale_info; + LLSelectMgr::instance().selectGetSaleInfo(sale_info); + + bool can_copy = itemp->getPermissions().allowCopyBy(gAgentID); // do we have perm to copy this texture? + bool can_transfer = itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID); // do we have perm to transfer this texture? + bool is_object_owner = gAgentID == obj_owner_id; // does object for which we are going to apply texture belong to the agent? + bool not_for_sale = !sale_info.isForSale(); // is object for which we are going to apply texture not for sale? + + if (can_copy && can_transfer) + { + texture_ctrl->setCanApply(true, true); + return; + } + + // if texture has (no-transfer) attribute it can be applied only for object which we own and is not for sale + texture_ctrl->setCanApply(false, can_transfer ? true : is_object_owner && not_for_sale); + + if (gSavedSettings.getBOOL("TextureLivePreview")) + { + LLNotificationsUtil::add("LivePreviewUnavailable"); + } + } +} + +// selection inside the texture/material picker changed +void FSPanelFace::onPbrSelectionChanged(LLInventoryItem* itemp) +{ + LLUUID obj_owner_id; + std::string obj_owner_name; + LLSelectMgr::instance().selectGetOwner(obj_owner_id, obj_owner_name); + + LLSaleInfo sale_info; + LLSelectMgr::instance().selectGetSaleInfo(sale_info); + + bool can_copy = itemp->getPermissions().allowCopyBy(gAgentID); // do we have perm to copy this material? + bool can_transfer = itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID); // do we have perm to transfer this material? + bool can_modify = itemp->getPermissions().allowOperationBy(PERM_MODIFY, gAgentID); // do we have perm to transfer this material? + bool is_object_owner = gAgentID == obj_owner_id; // does object for which we are going to apply material belong to the agent? + bool not_for_sale = !sale_info.isForSale(); // is object for which we are going to apply material not for sale? + + if (can_copy && can_transfer && can_modify) + { + mMaterialCtrlPBR->setCanApply(true, true); + return; + } + + // if material has (no-transfer) attribute it can be applied only for object which we own and is not for sale + mMaterialCtrlPBR->setCanApply(false, can_transfer ? true : is_object_owner && not_for_sale); + + if (gSavedSettings.getBOOL("TextureLivePreview")) + { + LLNotificationsUtil::add("LivePreviewUnavailablePBR"); + } +} + +bool FSPanelFace::isIdenticalPlanarTexgen() +{ + LLTextureEntry::e_texgen selected_texgen = LLTextureEntry::TEX_GEN_DEFAULT; + bool identical_texgen = false; + LLSelectedTE::getTexGen(selected_texgen, identical_texgen); + return (identical_texgen && (selected_texgen == LLTextureEntry::TEX_GEN_PLANAR)); +} + +void FSPanelFace::LLSelectedTE::getFace(LLFace*& face_to_return, bool& identical_face) +{ + struct LLSelectedTEGetFace : public LLSelectedTEGetFunctor + { + LLFace* get(LLViewerObject* object, S32 te) + { + return (object->mDrawable) ? object->mDrawable->getFace(te): NULL; + } + } get_te_face_func; + + identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, face_to_return, false, (LLFace*)nullptr); +} + +void FSPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face) +{ + LLGLenum image_format{ GL_RGB }; + struct LLSelectedTEGetImageFormat : public LLSelectedTEGetFunctor + { + LLGLenum get(LLViewerObject* object, S32 te_index) + { + LLViewerTexture* image = object->getTEImage(te_index); + return image ? image->getPrimaryFormat() : GL_RGB; + } + } get_glenum; + + identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_glenum, image_format); + image_format_to_return = image_format; +} + +void FSPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical) +{ + struct LLSelectedTEGetTexId : public LLSelectedTEGetFunctor + { + LLUUID get(LLViewerObject* object, S32 te_index) + { + LLTextureEntry *te = object->getTE(te_index); + if (te) + { + if ((te->getID() == IMG_USE_BAKED_EYES) || (te->getID() == IMG_USE_BAKED_HAIR) || (te->getID() == IMG_USE_BAKED_HEAD) || (te->getID() == IMG_USE_BAKED_LOWER) || (te->getID() == IMG_USE_BAKED_SKIRT) || (te->getID() == IMG_USE_BAKED_UPPER) + || (te->getID() == IMG_USE_BAKED_LEFTARM) || (te->getID() == IMG_USE_BAKED_LEFTLEG) || (te->getID() == IMG_USE_BAKED_AUX1) || (te->getID() == IMG_USE_BAKED_AUX2) || (te->getID() == IMG_USE_BAKED_AUX3)) + { + return te->getID(); + } + } + + LLUUID id; + LLViewerTexture* image = object->getTEImage(te_index); + if (image) + { + id = image->getID(); + } + + if (!id.isNull() && LLViewerMedia::getInstance()->textureHasMedia(id)) + { + if (te) + { + LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_STANDARD) : NULL; + if(!tex) + { + tex = LLViewerFetchedTexture::sDefaultImagep; + } + if (tex) + { + id = tex->getID(); + } + } + } + return id; + } + } func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, id ); +} + +void FSPanelFace::LLSelectedTEMaterial::getCurrent(LLMaterialPtr& material_ptr, bool& identical_material) +{ + struct MaterialFunctor : public LLSelectedTEGetFunctor + { + LLMaterialPtr get(LLViewerObject* object, S32 te_index) + { + return object->getTEref(te_index).getMaterialParams(); + } + } func; + + identical_material = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_ptr); +} + +void FSPanelFace::LLSelectedTEMaterial::getMaxSpecularRepeats(F32& repeats, bool& identical) +{ + struct LLSelectedTEGetMaxSpecRepeats : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + LLMaterial* mat = object->getTEref(face).getMaterialParams().get(); + U32 s_axis = VX; + U32 t_axis = VY; + F32 repeats_s = 1.0f; + F32 repeats_t = 1.0f; + if (mat) + { + mat->getSpecularRepeat(repeats_s, repeats_t); + repeats_s /= object->getScale().mV[s_axis]; + repeats_t /= object->getScale().mV[t_axis]; + } + return llmax(repeats_s, repeats_t); + } + + } max_spec_repeats_func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_spec_repeats_func, repeats); +} + +void FSPanelFace::LLSelectedTEMaterial::getMaxNormalRepeats(F32& repeats, bool& identical) +{ + struct LLSelectedTEGetMaxNormRepeats : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + LLMaterial* mat = object->getTEref(face).getMaterialParams().get(); + U32 s_axis = VX; + U32 t_axis = VY; + F32 repeats_s = 1.0f; + F32 repeats_t = 1.0f; + if (mat) + { + mat->getNormalRepeat(repeats_s, repeats_t); + repeats_s /= object->getScale().mV[s_axis]; + repeats_t /= object->getScale().mV[t_axis]; + } + return llmax(repeats_s, repeats_t); + } + + } max_norm_repeats_func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_norm_repeats_func, repeats); +} + +void FSPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, const bool diffuse_texture_has_alpha) +{ + struct LLSelectedTEGetDiffuseAlphaMode : public LLSelectedTEGetFunctor + { + LLSelectedTEGetDiffuseAlphaMode() : _isAlpha(false) {} + LLSelectedTEGetDiffuseAlphaMode(bool diffuse_texture_has_alpha) : _isAlpha(diffuse_texture_has_alpha) {} + virtual ~LLSelectedTEGetDiffuseAlphaMode() {} + + U8 get(LLViewerObject* object, S32 face) + { + U8 diffuse_mode = _isAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + + LLTextureEntry* tep = object->getTE(face); + if (tep) + { + LLMaterial* mat = tep->getMaterialParams().get(); + if (mat) + { + diffuse_mode = mat->getDiffuseAlphaMode(); + } + } + + return diffuse_mode; + } + + bool _isAlpha; // whether or not the diffuse texture selected contains alpha information + } get_diff_mode(diffuse_texture_has_alpha); + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &get_diff_mode, diffuse_alpha_mode); +} + +void FSPanelFace::LLSelectedTE::getObjectScaleS(F32& scale_s, bool& identical) +{ + struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + U32 s_axis = VX; + U32 t_axis = VY; + LLPrimitive::getTESTAxes(face, &s_axis, &t_axis); + return object->getScale().mV[s_axis]; + } + + } scale_s_func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &scale_s_func, scale_s ); +} + +void FSPanelFace::LLSelectedTE::getObjectScaleT(F32& scale_t, bool& identical) +{ + struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + U32 s_axis = VX; + U32 t_axis = VY; + LLPrimitive::getTESTAxes(face, &s_axis, &t_axis); + return object->getScale().mV[t_axis]; + } + + } scale_t_func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &scale_t_func, scale_t ); +} + +void FSPanelFace::LLSelectedTE::getMaxDiffuseRepeats(F32& repeats, bool& identical) +{ + struct LLSelectedTEGetMaxDiffuseRepeats : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + U32 s_axis = VX; + U32 t_axis = VY; + LLPrimitive::getTESTAxes(face, &s_axis, &t_axis); + F32 repeats_s = object->getTEref(face).mScaleS / object->getScale().mV[s_axis]; + F32 repeats_t = object->getTEref(face).mScaleT / object->getScale().mV[t_axis]; + return llmax(repeats_s, repeats_t); + } + + } max_diff_repeats_func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_diff_repeats_func, repeats ); +} + +void FSPanelFace::onClickMapsSync() +{ + getState(); + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + alignMaterialsProperties(); + } +} + +// used to be called from two places but onCommitFlip() now does it a different way +// so we end up with this still being a function but strictly it could be moved +// into onClickMapsSync() -Zi +void FSPanelFace::alignMaterialsProperties() +{ + // FIRE-11911: Synchronize materials doesn't work with planar textures + // Don't even try to do the alignment if we wind up here and planar is enabled. + if (mCheckPlanarAlign->getValue().asBoolean()) + { + return; + } + // FIRE-11911 + + F32 tex_scale_u = getCurrentTextureScaleU(); + F32 tex_scale_v = getCurrentTextureScaleV(); + F32 tex_offset_u = getCurrentTextureOffsetU(); + F32 tex_offset_v = getCurrentTextureOffsetV(); + F32 tex_rot = getCurrentTextureRot(); + + // FIRE-12275: Material offset not working correctly + // Since the server cannot store negative offsets for materials + // textures, we normalize them to equivalent positive values here. + tex_offset_u = (tex_offset_u < 0.0) ? 1.0 + tex_offset_u : tex_offset_u; + tex_offset_v = (tex_offset_v < 0.0) ? 1.0 + tex_offset_v : tex_offset_v; + // FIRE-12275 + + // FIRE-12831: Negative rotations revert to zero + // The same goes for rotations as for offsets. + tex_rot = (tex_rot < 0.0) ? 360.0 + tex_rot : tex_rot; + // FIRE-12831 + + mCtrlShinyScaleU->setValue(tex_scale_u); + mCtrlShinyScaleV->setValue(tex_scale_v); + mCtrlShinyOffsetU->setValue(tex_offset_u); + mCtrlShinyOffsetV->setValue(tex_offset_v); + mCtrlShinyRot->setValue(tex_rot); + + // What is this abomination!? -Zi + LLSelectedTEMaterial::setSpecularRepeatX(this, tex_scale_u); + LLSelectedTEMaterial::setSpecularRepeatY(this, tex_scale_v); + LLSelectedTEMaterial::setSpecularOffsetX(this, tex_offset_u); + LLSelectedTEMaterial::setSpecularOffsetY(this, tex_offset_v); + LLSelectedTEMaterial::setSpecularRotation(this, tex_rot * DEG_TO_RAD); + + mCtrlBumpyScaleU->setValue(tex_scale_u); + mCtrlBumpyScaleV->setValue(tex_scale_v); + mCtrlBumpyOffsetU->setValue(tex_offset_u); + mCtrlBumpyOffsetV->setValue(tex_offset_v); + mCtrlBumpyRot->setValue(tex_rot); + + // What is this abomination!? -Zi + LLSelectedTEMaterial::setNormalRepeatX(this, tex_scale_u); + LLSelectedTEMaterial::setNormalRepeatY(this, tex_scale_v); + LLSelectedTEMaterial::setNormalOffsetX(this, tex_offset_u); + LLSelectedTEMaterial::setNormalOffsetY(this, tex_offset_v); + LLSelectedTEMaterial::setNormalRotation(this, tex_rot * DEG_TO_RAD); +} + +void FSPanelFace::onCommitFlip(const LLSD& user_data) +{ + LL_WARNS() << "onCommitFlip" << LL_ENDL; + std::string control_name = user_data.asString(); + if (control_name.empty()) + { + LL_WARNS() << "empty user data!" << LL_ENDL; + return; + } + + LL_WARNS() << "control name: " << control_name << LL_ENDL; + + LLSpinCtrl* spinner = findChild(control_name); + if (spinner) + { + // TODO: compensate for normal/specular map doubling of values in planar mapping mode -Zi + F32 value = -(spinner->getValue().asReal()); + spinner->setValue(value); + spinner->forceEditorCommit(); + } + else + { + LL_WARNS() << "spinner not found: " << control_name << LL_ENDL; + } +} + +void FSPanelFace::changePrecision(S32 decimal_precision) +{ + mCtrlTexScaleU->setPrecision(decimal_precision); + mCtrlTexScaleV->setPrecision(decimal_precision); + mCtrlBumpyScaleU->setPrecision(decimal_precision); + mCtrlBumpyScaleV->setPrecision(decimal_precision); + mCtrlShinyScaleU->setPrecision(decimal_precision); + mCtrlShinyScaleV->setPrecision(decimal_precision); + mCtrlTexOffsetU->setPrecision(decimal_precision); + mCtrlTexOffsetV->setPrecision(decimal_precision); + mCtrlBumpyOffsetU->setPrecision(decimal_precision); + mCtrlBumpyOffsetV->setPrecision(decimal_precision); + mCtrlShinyOffsetU->setPrecision(decimal_precision); + mCtrlShinyOffsetV->setPrecision(decimal_precision); + mCtrlTexRot->setPrecision(decimal_precision); + mCtrlBumpyRot->setPrecision(decimal_precision); + mCtrlShinyRot->setPrecision(decimal_precision); + mCtrlRpt->setPrecision(decimal_precision); + // TODO: add PBR spinners -Zi +} + +// Find all faces with same texture +// TODO: not yet implemented in the new edit panel -Zi +void FSPanelFace::onClickBtnSelectSameTexture(const LLUICtrl* ctrl, const LLSD& user_data) +{ + char channel = user_data.asStringRef()[0]; + + std::unordered_set objects; + + // get a list of all linksets where at least one face is selected + for (auto iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) + { + objects.insert((*iter)->getObject()->getRootEdit()); + } + + // clean out the selection + LLSelectMgr::getInstance()->deselectAll(); + + // select all faces of all linksets that were found before + LLObjectSelectionHandle handle; + for(auto objectp : objects) + { + handle = LLSelectMgr::getInstance()->selectObjectAndFamily(objectp, true, false); + } + + // grab the texture ID from the texture selector + LLTextureCtrl* texture_control = mTextureCtrl; + if (channel == 'n') + { + texture_control = mBumpyTextureCtrl; + } + else if (channel == 's') + { + texture_control = mShinyTextureCtrl; + } + + LLUUID id = texture_control->getImageAssetID(); + + // go through all selected links in all selected linksets + for (auto iter = handle->begin(); iter != handle->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* objectp = node->getObject(); + + U8 te_count = objectp->getNumTEs(); + + for (U8 i = 0; i < te_count; i++) + { + LLUUID image_id; + if (channel == 'd') + { + image_id = objectp->getTEImage(i)->getID(); + } + else + { + const LLMaterialPtr mat = objectp->getTEref(i).getMaterialParams(); + if (mat.notNull()) + { + if (channel == 'n') + { + image_id = mat->getNormalID(); + } + else if (channel == 's') + { + image_id = mat->getSpecularID(); + } + } + } + + // deselect all faces that use a different texture UUID + if (image_id != id) + { + objectp->setTESelected(i, false); + node->selectTE(i, false); + } + } + } +} + +// +// convenience functions around tab containers -Zi +// + +S32 FSPanelFace::getCurrentMaterialType() const +{ + const std::string& tab_name = mTabsPBRMatMedia->getCurrentPanel()->getName(); + + if (tab_name == "panel_material_type_pbr") + { + return MATMEDIA_PBR; + } + else if (tab_name == "panel_material_type_media") + { + return MATMEDIA_MEDIA; + } + return MATMEDIA_MATERIAL; +} + +S32 FSPanelFace::getCurrentMatChannel() const +{ + const std::string& tab_name = mTabsMatChannel->getCurrentPanel()->getName(); + + if (tab_name == "panel_blinn_phong_normal") + { + return MATTYPE_NORMAL; + } + if (tab_name == "panel_blinn_phong_specular") + { + return MATTYPE_SPECULAR; + } + return MATTYPE_DIFFUSE; +} + +S32 FSPanelFace::getCurrentPBRChannel() const +{ + const std::string& tab_name = mTabsPBRChannel->getCurrentPanel()->getName(); + + if (tab_name == "panel_pbr_transforms_base_color") + { + return PBRTYPE_BASE_COLOR; + } + if (tab_name == "panel_pbr_transforms_normal") + { + return PBRTYPE_NORMAL; + } + if (tab_name == "panel_pbr_transforms_metallic") + { + return PBRTYPE_METALLIC_ROUGHNESS; // TODO: we use specular editor color for now -Zi + } + if (tab_name == "panel_pbr_transforms_emissive") + { + return PBRTYPE_EMISSIVE; // TODO: "emissive" has no defined editor color yet -Zi + } + return PBRTYPE_RENDER_MATERIAL_ID; +} + +void FSPanelFace::selectMaterialType(S32 material_type) +{ + if (material_type == MATMEDIA_PBR) + { + mTabsPBRMatMedia->selectTabByName("panel_material_type_pbr"); + } + else if (material_type == MATMEDIA_MEDIA) + { + mTabsPBRMatMedia->selectTabByName("panel_material_type_media"); + } + else + { + mTabsPBRMatMedia->selectTabByName("panel_material_type_blinn_phong"); + } + onMatTabChange(); // set up relative to active tab +} + +void FSPanelFace::selectMatChannel(S32 mat_channel) +{ + if (mat_channel == MATTYPE_NORMAL) + { + mTabsMatChannel->selectTabByName("panel_blinn_phong_normal"); + } + else if (mat_channel == MATTYPE_SPECULAR) + { + mTabsMatChannel->selectTabByName("panel_blinn_phong_specular"); + } + else + { + mTabsMatChannel->selectTabByName("panel_blinn_phong_diffuse"); + } +} + +void FSPanelFace::selectPBRChannel(S32 pbr_channel) +{ + if (pbr_channel == PBRTYPE_NORMAL) + { + mTabsMatChannel->selectTabByName("panel_pbr_transforms_base_color"); + } + else if (pbr_channel == PBRTYPE_BASE_COLOR) + { + mTabsMatChannel->selectTabByName("panel_pbr_transforms_normal"); + } + else if (pbr_channel == PBRTYPE_METALLIC_ROUGHNESS) + { + mTabsMatChannel->selectTabByName("panel_pbr_transforms_metallic"); + } + else if (pbr_channel == PBRTYPE_EMISSIVE) + { + mTabsMatChannel->selectTabByName("panel_pbr_transforms_emissive"); + } + else + { + mTabsMatChannel->selectTabByName("panel_pbr_transforms_all"); + } +} diff --git a/indra/newview/fspanelface.h b/indra/newview/fspanelface.h new file mode 100644 index 0000000000..e73a2cb593 --- /dev/null +++ b/indra/newview/fspanelface.h @@ -0,0 +1,804 @@ +/** + * @file fspanelface.h + * @brief Consolidated materials/texture panel in the tools floater + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2024, Zi Ree@Second Life + * + * 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 FS_FSPANELFACE_H +#define FS_FSPANELFACE_H + +#include "v4color.h" +#include "llpanel.h" +#include "llgltfmaterial.h" +#include "llmaterial.h" +#include "llmaterialmgr.h" +#include "lltextureentry.h" +#include "llselectmgr.h" + +#include + +class LLButton; +class LLCheckBoxCtrl; +class LLColorSwatchCtrl; +class LLComboBox; +class LLInventoryItem; +class LLLineEditor; +class LLRadioGroup; +class LLSpinCtrl; +class LLTextBox; +class LLTextureCtrl; +class LLUICtrl; +class LLViewerObject; +class LLFloater; +class LLMaterialID; +class LLMediaCtrl; +class LLMenuButton; + +class PBRPickerAgentListener; +class PBRPickerObjectListener; + +class LLTabContainer; + +// Represents an edit for use in replicating the op across one or more materials in the selection set. +// +// The apply function optionally performs the edit which it implements +// as a functor taking Data that calls member func MaterialFunc taking SetValueType +// on an instance of the LLMaterial class. +// +// boost who? +// +template< + typename DataType, + typename SetValueType, + void (LLMaterial::*MaterialEditFunc)(SetValueType data) > +class FSMaterialEditFunctor +{ +public: + FSMaterialEditFunctor(const DataType& data) : _data(data) {} + virtual ~FSMaterialEditFunctor() {} + virtual void apply(LLMaterialPtr& material) { (material->*(MaterialEditFunc))(_data); } + DataType _data; +}; + +template< + typename DataType, + DataType (LLMaterial::*MaterialGetFunc)() > +class FSMaterialGetFunctor +{ +public: + FSMaterialGetFunctor() {} + virtual DataType get(LLMaterialPtr& material) { return (material->*(MaterialGetFunc)); } +}; + +template< + typename DataType, + DataType (LLTextureEntry::*TEGetFunc)() > +class FSTEGetFunctor +{ +public: + FSTEGetFunctor() {} + virtual DataType get(LLTextureEntry* entry) { return (entry*(TEGetFunc)); } +}; + +// +// main class +// + +class FSPanelFace : public LLPanel +{ +public: + FSPanelFace(); + virtual ~FSPanelFace(); + + virtual BOOL postBuild(); + + void refresh(); + void refreshMedia(); + void unloadMedia(); + void changePrecision(S32 decimal_precision); // Adjustable decimal precision + + static void onMaterialOverrideReceived(const LLUUID& object_id, S32 side); + + /*virtual*/ void onVisibilityChange(BOOL new_visibility); + /*virtual*/ void draw(); + + LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material); + + LLRender::eTexIndex getTextureChannelToEdit(); + LLRender::eTexIndex getTextureDropChannel(); + + LLGLTFMaterial::TextureInfo getPBRDropChannel(); + +protected: + void navigateToTitleMedia(const std::string url); + bool selectedMediaEditable(); + void clearMediaSettings(); + void updateMediaSettings(); + void updateMediaTitle(); + + void getState(); + + void sendTexture(); // applies and sends texture + void sendTextureInfo(); // applies and sends texture scale, offset, etc. + void sendColor(); // applies and sends color + void sendAlpha(); // applies and sends transparency + void sendBump(U32 bumpiness); // applies and sends bump map + void sendTexGen(); // applies and sends bump map + void sendShiny(U32 shininess); // applies and sends shininess + void sendFullbright(); // applies and sends full bright + void sendGlow(); + void alignTextureLayer(); + + void updateCopyTexButton(); + + // + // UI Callbacks + // + + // common controls and parameters for Blinn-Phong and PBR + void onCopyFaces(); // Extended copy & paste buttons + void onPasteFaces(); + void onCommitGlow(); + void onCommitRepeatsPerMeter(); + + // Blinn-Phong alpha parameters + void onCommitAlpha(); + void onCommitAlphaMode(); + void onCommitMaterialMaskCutoff(); + void onCommitFullbright(); + + // Blinn-Phong texture transforms and controls + void onCommitTexGen(); + void onCommitPlanarAlign(); + void onCommitBump(); + void onCommitShiny(); + void onCommitTextureScaleX(); + void onCommitTextureScaleY(); + void onCommitTextureOffsetX(); + void onCommitTextureOffsetY(); + void onCommitTextureRot(); + void onCommitMaterialBumpyScaleX(); + void onCommitMaterialBumpyScaleY(); + void onCommitMaterialBumpyOffsetX(); + void onCommitMaterialBumpyOffsetY(); + void onCommitMaterialBumpyRot(); + void onCommitMaterialShinyScaleX(); + void onCommitMaterialShinyScaleY(); + void onCommitMaterialShinyOffsetX(); + void onCommitMaterialShinyOffsetY(); + void onCommitMaterialShinyRot(); + void onCommitMaterialGloss(); + void onCommitMaterialEnv(); + + // Blinn-Phong Diffuse tint color swatch + void onCommitColor(); + void onCancelColor(); + void onSelectColor(); + + // Blinn-Phong Diffuse texture swatch + void onCommitTexture(const LLUICtrl* ctrl, const LLSD& data); + void onCancelTexture(); + BOOL onDragTexture(LLInventoryItem* item); // this function is to return TRUE if the drag should succeed. + void onCloseTexturePicker(const LLSD& data); + + // Blinn-Phong Normal texture swatch + void onCommitNormalTexture(const LLUICtrl* ctrl, const LLSD& data); + void onCancelNormalTexture(); + + // Blinn-Phong Specular texture swatch + void onCommitSpecularTexture(const LLUICtrl* ctrl, const LLSD& data); + void onCancelSpecularTexture(); + + // Blinn-Phong Specular tint color swatch + void onCommitShinyColor(); + void onCancelShinyColor(); + void onSelectShinyColor(); + + // Texture alignment and maps synchronization + void onClickAutoFix(); + void onAlignTexture(); + void onClickMapsSync(); + + /* + * Checks whether the selected texture from the LLFloaterTexturePicker can be applied to the currently selected object. + * If agent selects texture which is not allowed to be applied for the currently selected object, + * all controls of the floater texture picker which allow to apply the texture will be disabled. + */ + void onTextureSelectionChanged(const std::string& which_control); + + // Media + void onClickBtnEditMedia(); + void onClickBtnDeleteMedia(); + void onClickBtnAddMedia(); + + void alignMaterialsProperties(); + + // + // PBR + // + + // PBR Material + void onCommitPbr(); + void onCancelPbr(); + void onSelectPbr(); + BOOL onDragPbr(LLInventoryItem* item); // this function is to return TRUE if the drag should succeed. + + void onPbrSelectionChanged(LLInventoryItem* itemp); + void onClickBtnSavePBR(); + + void updatePBROverrideDisplay(); + + // PBR texture maps + void onCommitPbr(const LLUICtrl* pbr_ctrl); + void onCancelPbr(const LLUICtrl* pbr_ctrl); + void onSelectPbr(const LLUICtrl* pbr_ctrl); + + void getGLTFMaterial(LLGLTFMaterial* mat); + + // + // other + // + + bool deleteMediaConfirm(const LLSD& notification, const LLSD& response); + bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response); + + // Make UI reflect state of currently selected material (refresh) + // and UI mode (e.g. editing normal map v diffuse map) + // + // @param force_set_values forces spinners to set value even if they are focused + void updateUI(bool force_set_values = false); + + // Convenience func to determine if all faces in selection have + // identical planar texgen settings during edits + // + bool isIdenticalPlanarTexgen(); + + // Callback funcs for individual controls + // + static void syncRepeatX(FSPanelFace* self, F32 scaleU); + static void syncRepeatY(FSPanelFace* self, F32 scaleV); + static void syncOffsetX(FSPanelFace* self, F32 offsetU); + static void syncOffsetY(FSPanelFace* self, F32 offsetV); + static void syncMaterialRot(FSPanelFace* self, F32 rot, int te = -1); + + // unify all GLTF spinners with no switching around required -Zi + void onCommitGLTFUVSpinner(const LLUICtrl* ctrl, const LLSD& user_data); + + void onClickBtnSelectSameTexture(const LLUICtrl* ctrl, const LLSD& user_data); // Find all faces with same texture + +public: // needs to be accessible to selection manager + void onCopyColor(); // records all selected faces + void onPasteColor(); // to specific face + void onPasteColor(LLViewerObject* objectp, S32 te); // to specific face + void onCopyTexture(); + void onPasteTexture(); + void onPasteTexture(LLViewerObject* objectp, S32 te); + +protected: + // + // Constant definitions for tabs and combo boxes + // Must match the commbobox definitions in panel_tools_texture.xml // Not anymore -Zi + // + static constexpr S32 MATMEDIA_MATERIAL = 0; // Material + static constexpr S32 MATMEDIA_PBR = 1; // PBR + static constexpr S32 MATMEDIA_MEDIA = 2; // Media + + static constexpr S32 MATTYPE_DIFFUSE = 0; // Diffuse material texture + static constexpr S32 MATTYPE_NORMAL = 1; // Normal map + static constexpr S32 MATTYPE_SPECULAR = 2; // Specular map + + static constexpr S32 BUMPY_TEXTURE = 18; // use supplied normal map (index of "Use Texture" in combo box) + static constexpr S32 SHINY_TEXTURE = 4; // use supplied specular map (index of "Use Texture" in combo box) + + static constexpr S32 PBRTYPE_RENDER_MATERIAL_ID = 0; // Render Material ID + static constexpr S32 PBRTYPE_BASE_COLOR = 1; // PBR Base Color + static constexpr S32 PBRTYPE_METALLIC_ROUGHNESS = 2; // PBR Metallic + static constexpr S32 PBRTYPE_EMISSIVE = 3; // PBR Emissive + static constexpr S32 PBRTYPE_NORMAL = 4; // PBR Normal + static constexpr S32 PBRTYPE_COUNT = 5; // number of PBR map types + +public: + // public because ... functors? -Zi + void onCommitFlip(const LLSD& user_data); + + // Blinn-Phong texture transforms and controls + // public because ... functors? -Zi + LLSpinCtrl* mCtrlTexScaleU; + LLSpinCtrl* mCtrlTexScaleV; + LLSpinCtrl* mCtrlBumpyScaleU; + LLSpinCtrl* mCtrlBumpyScaleV; + LLSpinCtrl* mCtrlShinyScaleU; + LLSpinCtrl* mCtrlShinyScaleV; + LLSpinCtrl* mCtrlTexOffsetU; + LLSpinCtrl* mCtrlTexOffsetV; + LLSpinCtrl* mCtrlBumpyOffsetU; + LLSpinCtrl* mCtrlBumpyOffsetV; + LLSpinCtrl* mCtrlShinyOffsetU; + LLSpinCtrl* mCtrlShinyOffsetV; + LLSpinCtrl* mCtrlTexRot; + LLSpinCtrl* mCtrlBumpyRot; + LLSpinCtrl* mCtrlShinyRot; + + // Blinn-Phong texture transforms and controls + // public to give functors access -Zi + LLComboBox* mComboTexGen; + LLCheckBoxCtrl* mCheckPlanarAlign; + + // Tab controls + // public to give functors access -Zi + LLTabContainer* mTabsMatChannel; + void onMatTabChange(); + +private: + bool isAlpha() { return mIsAlpha; } + + // Update visibility of controls to match current UI mode + // (e.g. materials vs media editing) + // + // Do NOT call updateUI from within this function. + // + void updateVisibility(LLViewerObject* objectp = nullptr); + + // Convenience funcs to keep the visual flack to a minimum + // + LLUUID getCurrentNormalMap(); + LLUUID getCurrentSpecularMap(); + U32 getCurrentShininess(); + U32 getCurrentBumpiness(); + U8 getCurrentDiffuseAlphaMode(); + U8 getCurrentAlphaMaskCutoff(); + U8 getCurrentEnvIntensity(); + U8 getCurrentGlossiness(); + F32 getCurrentBumpyRot(); + F32 getCurrentBumpyScaleU(); + F32 getCurrentBumpyScaleV(); + F32 getCurrentBumpyOffsetU(); + F32 getCurrentBumpyOffsetV(); + F32 getCurrentShinyRot(); + F32 getCurrentShinyScaleU(); + F32 getCurrentShinyScaleV(); + F32 getCurrentShinyOffsetU(); + F32 getCurrentShinyOffsetV(); + + // map tab states to various values + // TODO: should be done with tab-change signals and flags, really + S32 getCurrentMaterialType() const; + S32 getCurrentMatChannel() const; + S32 getCurrentPBRChannel() const; + void selectMaterialType(S32 material_type); + void selectMatChannel(S32 mat_channel); + void selectPBRChannel(S32 pbr_channel); + + F32 getCurrentTextureRot(); + F32 getCurrentTextureScaleU(); + F32 getCurrentTextureScaleV(); + F32 getCurrentTextureOffsetU(); + F32 getCurrentTextureOffsetV(); + + // + // Build tool controls + // + + // private Tab controls + LLTabContainer* mTabsPBRMatMedia; + LLTabContainer* mTabsPBRChannel; + + // common controls and parameters for Blinn-Phong and PBR + LLButton* mBtnCopyFaces; + LLButton* mBtnPasteFaces; + LLSpinCtrl* mCtrlGlow; + LLSpinCtrl* mCtrlRpt; + + // Blinn-Phong alpha parameters + LLSpinCtrl* mCtrlColorTransp; // transparency = 1 - alpha + LLView* mColorTransPercent; + LLTextBox* mLabelAlphaMode; + LLComboBox* mComboAlphaMode; + LLSpinCtrl* mCtrlMaskCutoff; + LLCheckBoxCtrl* mCheckFullbright; + + // private Blinn-Phong texture transforms and controls + LLView* mLabelTexGen; + LLView* mLabelBumpiness; + LLComboBox* mComboBumpiness; + LLView* mLabelShininess; + LLComboBox* mComboShininess; + // others are above in the public section + LLSpinCtrl* mCtrlGlossiness; + LLSpinCtrl* mCtrlEnvironment; + + // Blinn-Phong Diffuse tint color swatch + LLColorSwatchCtrl* mColorSwatch; + + // Blinn-Phong Diffuse texture swatch + LLTextureCtrl* mTextureCtrl; + + // Blinn-Phong Normal texture swatch + LLTextureCtrl* mBumpyTextureCtrl; + + // Blinn-Phong Specular texture swatch + LLTextureCtrl* mShinyTextureCtrl; + + // Blinn-Phong Specular tint color swatch + LLColorSwatchCtrl* mShinyColorSwatch; + + // Texture alignment and maps synchronization + LLButton* mBtnAlignMedia; + LLButton* mBtnAlignTextures; + LLCheckBoxCtrl* mCheckSyncMaterials; + + // Media + LLButton* mBtnDeleteMedia; + LLButton* mBtnAddMedia; + LLMediaCtrl* mTitleMedia; + LLTextBox* mTitleMediaText; + + // PBR + LLTextureCtrl* mMaterialCtrlPBR; + LLColorSwatchCtrl* mBaseTintPBR; + LLTextureCtrl* mBaseTexturePBR; + LLTextureCtrl* mNormalTexturePBR; + LLTextureCtrl* mORMTexturePBR; + LLTextureCtrl* mEmissiveTexturePBR; + LLColorSwatchCtrl* mEmissiveTintPBR; + LLCheckBoxCtrl* mCheckDoubleSidedPBR; + LLSpinCtrl* mAlphaPBR; + LLTextBox* mLabelAlphaModePBR; + LLComboBox* mAlphaModePBR; + LLSpinCtrl* mMaskCutoffPBR; + LLSpinCtrl* mMetallicFactorPBR; + LLSpinCtrl* mRoughnessFactorPBR; + LLButton* mBtnSavePBR; + + struct + { + std::array mMap; + LLColor4 mBaseColorTint; + F32 mMetallic; + F32 mRoughness; + LLColor4 mEmissiveTint; + LLGLTFMaterial::AlphaMode mAlphaMode; + F32 mAlphaCutoff; + bool mDoubleSided; + } mPBRBaseMaterialParams; + + // map PBR material map types to glTF material types + LLGLTFMaterial::TextureInfo mPBRChannelToTextureInfo[PBRTYPE_COUNT] = + { + LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT, // PBRTYPE_RENDER_MATERIAL_ID + LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR, // PBRTYPE_BASE_COLOR + LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, // PBRTYPE_METALLIC_ROUGHNESS + LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE, // PBRTYPE_EMISSIVE + LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL // PBRTYPE_NORMAL + }; + + // Dirty flags - taken from llmaterialeditor.cpp ... LL please put this in a .h! -Zi + U32 mUnsavedChanges; // flags to indicate individual changed parameters + + // Hey look everyone, a type-safe alternative to copy and paste! :) + // + + // Update material parameters by applying 'edit_func' to selected TEs + // + template< + typename DataType, + typename SetValueType, + void (LLMaterial::*MaterialEditFunc)(SetValueType data) > + static void edit(FSPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID()) + { + FSMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc > edit(data); + struct LLSelectedTEEditMaterial : public LLSelectedTEMaterialFunctor + { + LLSelectedTEEditMaterial(FSPanelFace* panel, FSMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* editp, const LLUUID &only_for_object_id) : _panel(panel), _edit(editp), _only_for_object_id(only_for_object_id) {} + virtual ~LLSelectedTEEditMaterial() {}; + virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material) + { + if (_edit && (_only_for_object_id.isNull() || _only_for_object_id == object->getID())) + { + LLMaterialPtr new_material = _panel->createDefaultMaterial(current_material); + llassert_always(new_material); + + // Determine correct alpha mode for current diffuse texture + // (i.e. does it have an alpha channel that makes alpha mode useful) + // + // _panel->isAlpha() "lies" when one face has alpha and the rest do not (NORSPEC-329) + // need to get per-face answer to this question for sane alpha mode retention on updates. + // + bool is_alpha_face = object->isImageAlphaBlended(face); + + // need to keep this original answer for valid comparisons in logic below + // + U8 original_default_alpha_mode = is_alpha_face ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + + U8 default_alpha_mode = original_default_alpha_mode; + + if (!current_material.isNull()) + { + default_alpha_mode = current_material->getDiffuseAlphaMode(); + } + + // Insure we don't inherit the default of blend by accident... + // this will be stomped by a legit request to change the alpha mode by the apply() below + // + new_material->setDiffuseAlphaMode(default_alpha_mode); + + // Do "It"! + // + _edit->apply(new_material); + + U32 new_alpha_mode = new_material->getDiffuseAlphaMode(); + LLUUID new_normal_map_id = new_material->getNormalID(); + LLUUID new_spec_map_id = new_material->getSpecularID(); + + if ((new_alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) && !is_alpha_face) + { + new_alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + new_material->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE); + } + + bool is_default_blend_mode = (new_alpha_mode == original_default_alpha_mode); + bool is_need_material = !is_default_blend_mode || !new_normal_map_id.isNull() || !new_spec_map_id.isNull(); + + if (!is_need_material) + { + LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL; + LLMaterialMgr::getInstance()->remove(object->getID(),face); + new_material = NULL; + } + else + { + LL_DEBUGS("Materials") << "Putting material on object " << object->getID() << " face " << face << ", material: " << new_material->asLLSD() << LL_ENDL; + LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material); + } + + object->setTEMaterialParams(face, new_material); + return new_material; + } + return NULL; + } + FSMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* _edit; + FSPanelFace *_panel; + const LLUUID & _only_for_object_id; + } editor(p, &edit, only_for_object_id); + LLSelectMgr::getInstance()->selectionSetMaterialParams(&editor, te); + } + + template< + typename DataType, + typename ReturnType, + ReturnType (LLMaterial::* const MaterialGetFunc)() const > + static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value, bool has_tolerance = false, DataType tolerance = DataType()) + { + DataType data_value = default_value; + struct GetTEMaterialVal : public LLSelectedTEGetFunctor + { + GetTEMaterialVal(DataType default_value) : _default(default_value) {} + virtual ~GetTEMaterialVal() {} + + DataType get(LLViewerObject* object, S32 face) + { + DataType ret = _default; + LLMaterialPtr material_ptr; + LLTextureEntry* tep = object ? object->getTE(face) : NULL; + if (tep) + { + material_ptr = tep->getMaterialParams(); + if (!material_ptr.isNull()) + { + ret = (material_ptr->*(MaterialGetFunc))(); + } + } + return ret; + } + DataType _default; + } GetFunc(default_value); + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetFunc, data_value, has_tolerance, tolerance); + data_to_return = data_value; + } + + template< + typename DataType, + typename ReturnType, // some kids just have to different... + ReturnType (LLTextureEntry::* const TEGetFunc)() const > + static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value, bool has_tolerance = false, DataType tolerance = DataType()) + { + DataType data_value = default_value; + struct GetTEVal : public LLSelectedTEGetFunctor + { + GetTEVal(DataType default_value) : _default(default_value) {} + virtual ~GetTEVal() {} + + DataType get(LLViewerObject* object, S32 face) { + LLTextureEntry* tep = object ? object->getTE(face) : NULL; + return tep ? ((tep->*(TEGetFunc))()) : _default; + } + DataType _default; + } GetTEValFunc(default_value); + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetTEValFunc, data_value, has_tolerance, tolerance ); + data_to_return = data_value; + } + + // Update vis and enabling of specific subsets of controls based on material params + // (e.g. hide the spec controls if no spec texture is applied) + // + void updateShinyControls(bool is_setting_texture = false, bool mess_with_combobox = false); + void updateBumpyControls(bool is_setting_texture = false, bool mess_with_combobox = false); + void updateAlphaControls(); + void updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool& has_faces_without_pbr, bool force_set_values); + + void updateSelectedGLTFMaterials(std::function func); + void updateGLTFTextureTransform(float value, U32 pbr_type, std::function edit); + + void setMaterialOverridesFromSelection(); + + bool mIsAlpha; + + LLSD mClipboardParams; + + LLSD mMediaSettings; + bool mNeedMediaTitle; + + class Selection + { + public: + void connect(); + + // Returns true if the selected objects or sides have changed since + // this was last called, and no object update is pending + bool update(); + + // Prevents update() returning true until the provided object is + // updated. Necessary to prevent controls updating when the mouse is + // held down. + void setDirty() { mChanged = true; }; + + // Callbacks + void onSelectionChanged() { mNeedsSelectionCheck = true; } + void onSelectedObjectUpdated(const LLUUID &object_id, S32 side); + + protected: + bool compareSelection(); + + bool mChanged = false; + + boost::signals2::scoped_connection mSelectConnection; + bool mNeedsSelectionCheck = true; + S32 mSelectedObjectCount = 0; + S32 mSelectedTECount = 0; + LLUUID mSelectedObjectID; + S32 mLastSelectedSide = -1; + }; + + static Selection sMaterialOverrideSelection; + + std::unique_ptr mAgentInventoryListener; + std::unique_ptr mVOInventoryListener; + +public: + #if defined(FS_DEF_GET_MAT_STATE) + #undef FS_DEF_GET_MAT_STATE + #endif + + #if defined(FS_DEF_GET_TE_STATE) + #undef FS_DEF_GET_TE_STATE + #endif + + #if defined(FS_DEF_EDIT_MAT_STATE) + FS_DEF_EDIT_MAT_STATE + #endif + + // Accessors for selected TE material state + // + #define FS_DEF_GET_MAT_STATE(DataType,ReturnType,MaterialMemberFunc,DefaultValue,HasTolerance,Tolerance) \ + static void MaterialMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance) \ + { \ + getTEMaterialValue< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance); \ + } + + // Mutators for selected TE material + // + #define FS_DEF_EDIT_MAT_STATE(DataType,ReturnType,MaterialMemberFunc) \ + static void MaterialMemberFunc(FSPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID()) \ + { \ + edit< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(p, data, te, only_for_object_id); \ + } + + // Accessors for selected TE state proper (legacy settings etc) + // + #define FS_DEF_GET_TE_STATE(DataType,ReturnType,TexEntryMemberFunc,DefaultValue,HasTolerance,Tolerance) \ + static void TexEntryMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance) \ + { \ + getTEValue< DataType, ReturnType, &LLTextureEntry::TexEntryMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance); \ + } + + class LLSelectedTEMaterial + { + public: + static void getCurrent(LLMaterialPtr& material_ptr, bool& identical_material); + static void getMaxSpecularRepeats(F32& repeats, bool& identical); + static void getMaxNormalRepeats(F32& repeats, bool& identical); + static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha); + + FS_DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null, false, LLUUID::null) + FS_DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null, false, LLUUID::null) + FS_DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatX,1.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatY,1.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetX,0.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetY,0.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getSpecularRotation,0.0f, true, 0.001f) + + FS_DEF_GET_MAT_STATE(F32,F32,getNormalRepeatX,1.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getNormalRepeatY,1.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getNormalOffsetX,0.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getNormalOffsetY,0.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getNormalRotation,0.0f, true, 0.001f) + + FS_DEF_EDIT_MAT_STATE(U8,U8,setDiffuseAlphaMode); + FS_DEF_EDIT_MAT_STATE(U8,U8,setAlphaMaskCutoff); + + FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetX); + FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetY); + FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatX); + FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatY); + FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalRotation); + + FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetX); + FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetY); + FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatX); + FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatY); + FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularRotation); + + FS_DEF_EDIT_MAT_STATE(U8,U8,setEnvironmentIntensity); + FS_DEF_EDIT_MAT_STATE(U8,U8,setSpecularLightExponent); + + FS_DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID); + FS_DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID); + FS_DEF_EDIT_MAT_STATE(LLColor4U, const LLColor4U&,setSpecularLightColor); + }; + + class LLSelectedTE + { + public: + static void getFace(class LLFace*& face_to_return, bool& identical_face); + static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face); + static void getTexId(LLUUID& id, bool& identical); + static void getObjectScaleS(F32& scale_s, bool& identical); + static void getObjectScaleT(F32& scale_t, bool& identical); + static void getMaxDiffuseRepeats(F32& repeats, bool& identical); + + FS_DEF_GET_TE_STATE(U8,U8,getBumpmap,0, false, 0) + FS_DEF_GET_TE_STATE(U8,U8,getShiny,0, false, 0) + FS_DEF_GET_TE_STATE(U8,U8,getFullbright,0, false, 0) + FS_DEF_GET_TE_STATE(F32,F32,getRotation,0.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(F32,F32,getOffsetS,0.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(F32,F32,getOffsetT,0.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(F32,F32,getScaleS,1.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(F32,F32,getGlow,0.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT, false, LLTextureEntry::TEX_GEN_DEFAULT) + FS_DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white, false, LLColor4::black); + }; +}; + +#endif diff --git a/indra/newview/fspanelprefs.cpp b/indra/newview/fspanelprefs.cpp index 0f2bf603bd..001add788a 100644 --- a/indra/newview/fspanelprefs.cpp +++ b/indra/newview/fspanelprefs.cpp @@ -70,7 +70,7 @@ BOOL FSPanelPrefs::postBuild() LLTextureCtrl* tex_ctrl = getChild("texture control"); tex_ctrl->setCommitCallback(boost::bind(&FSPanelPrefs::onCommitTexture, this, _2)); - tex_ctrl->setDefaultImageAssetID(LLUUID(gSavedSettings.getString("DefaultObjectTexture"))); + tex_ctrl->setDefaultImageAssetID(DEFAULT_OBJECT_TEXTURE); mInvDropTarget = getChild("embed_item"); mInvDropTarget->setDADCallback(boost::bind(&FSPanelPrefs::onDADEmbeddedItem, this, _1)); diff --git a/indra/newview/fsslurl.cpp b/indra/newview/fsslurl.cpp index 86e7b9794e..31f061cc67 100644 --- a/indra/newview/fsslurl.cpp +++ b/indra/newview/fsslurl.cpp @@ -66,14 +66,14 @@ LLSLURL::LLSLURL(const std::string& slurl) // by default we go to agni. mType = INVALID; LL_DEBUGS("AppInit", "SLURL") << "SLURL: " << slurl << LL_ENDL; - if(slurl == SIM_LOCATION_HOME) - { - mType = HOME_LOCATION; - } - else if(slurl.empty() || (slurl == SIM_LOCATION_LAST)) + if (slurl.empty() || (slurl == SIM_LOCATION_LAST)) { mType = LAST_LOCATION; } + else if (slurl == SIM_LOCATION_HOME) + { + mType = HOME_LOCATION; + } else { LLURI slurl_uri; @@ -154,6 +154,15 @@ LLSLURL::LLSLURL(const std::string& slurl) if(slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME) { LL_DEBUGS("SLURL") << "secondlife scheme" << LL_ENDL; + if (path_array.size() == 0 + && slurl_uri.authority().empty() + && slurl_uri.escapedQuery().empty()) + { + mType = EMPTY; + // um, we need a path... + return; + } + // parse a maingrid style slurl. We know the grid is maingrid // so grab it. // A location slurl for maingrid (with the special schemes) can be in the form @@ -676,28 +685,24 @@ std::string LLSLURL::asString() const // std::string LLSLURL::getTypeHumanReadable(SLURL_TYPE type) { - std::string ret; switch(type) { case INVALID: - ret = "INVALID"; - break; + return "INVALID"; case LOCATION: - ret = "LOCATION"; - break; + return "LOCATION"; case HOME_LOCATION: - ret = "HOME_LOCATION"; - break; + return "HOME_LOCATION"; case LAST_LOCATION: - ret = "LAST_LOCATION"; - break; + return "LAST_LOCATION"; case APP: - ret = "APP"; - break; + return "APP"; case HELP: - ret = "HELP"; + return "HELP"; + case EMPTY: + return "EMPTY"; + default: + return{}; } - - return ret; } // diff --git a/indra/newview/fsslurl.h b/indra/newview/fsslurl.h index a3bd8e495b..03eb95853a 100644 --- a/indra/newview/fsslurl.h +++ b/indra/newview/fsslurl.h @@ -60,7 +60,8 @@ public: HOME_LOCATION, LAST_LOCATION, APP, - HELP + HELP, + EMPTY }; LLSLURL(): mType(INVALID) { } diff --git a/indra/newview/installers/darwin/apple-notarize.sh b/indra/newview/installers/darwin/apple-notarize.sh index ce012d84ed..cd3f9eb803 100755 --- a/indra/newview/installers/darwin/apple-notarize.sh +++ b/indra/newview/installers/darwin/apple-notarize.sh @@ -11,45 +11,30 @@ if [[ -f "$CONFIG_FILE" ]]; then zip_file=${app_file/app/zip} ditto -c -k --keepParent "$app_file" "$zip_file" if [[ -f "$zip_file" ]]; then - res=$(xcrun altool --notarize-app --primary-bundle-id "org.firestormviewer.firestorm" \ - --username $USERNAME \ - --password $PASSWORD \ - --asc-provider $ASC_PROVIDER \ - --file "$zip_file" 2>&1) + # res=$(xcrun notarytool store-credentials \ + # viewer.profile \ + # --verbose 2>*1) + # echo $res + res=$(xcrun notarytool submit "$zip_file" \ + --apple-id $USERNAME \ + --password $PASSWORD \ + --team-id $ASC_PROVIDER \ + --wait 2>&1) + echo "Notarytool submit:" echo $res - requestUUID=$(echo $res | awk '/RequestUUID/ { print $NF; }') - if [[ -n $requestUUID ]]; then - in_progress=1 - while [[ $in_progress -eq 1 ]]; do - sleep 30 - res=$(xcrun altool --notarization-info "$requestUUID" \ - --username $USERNAME \ - --password $PASSWORD 2>&1) - if [[ $res != *"in progress"* ]]; then - in_progress=0 - fi - echo "." - done - # log results - echo $res + [[ "$res" =~ 'id: '([^[:space:]]+) ]] + match=$? + echo "Notarized with id: [$match]" - #remove temporary file - rm "$zip_file" - - if [[ $res == *"success"* ]]; then - xcrun stapler staple "$app_file" - exit 0 - elif [[ $res == *"invalid"* ]]; then - echo "Notarization error: failed to process the app file" - exit 1 - else - echo "Notarization error: unknown response status" - fi - else - echo "Notarization error: couldn't get request UUID" - exit 1 - fi + # if [[ ! $match -eq 0 ]]; then + echo "Running Stapler" + xcrun stapler staple "$app_file" + exit 0 + # else + # echo "Notarization error" + # exit 1 + # fi else echo "Notarization error: ditto failed" exit 1 diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index f586a64575..f25906552c 100644 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -179,6 +179,7 @@ void LLAppCoreHttp::init() } else { + LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS("Init") << "Missing CA File; should be at " << ca_file << LL_ENDL; } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index de41f60012..30b4c3d734 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -392,7 +392,6 @@ BOOL gRandomizeFramerate = FALSE; BOOL gPeriodicSlowFrame = FALSE; BOOL gCrashOnStartup = FALSE; -BOOL gLLErrorActivated = FALSE; BOOL gLogoutInProgress = FALSE; BOOL gSimulateMemLeak = FALSE; @@ -2214,6 +2213,9 @@ bool LLAppViewer::cleanup() LL_INFOS() << "ViewerWindow deleted" << LL_ENDL; } + LLSplashScreen::show(); + LLSplashScreen::update(LLTrans::getString("ShuttingDown")); + LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL; // viewer UI relies on keyboard so keep it aound until viewer UI isa gone @@ -2530,6 +2532,8 @@ bool LLAppViewer::cleanup() // deleteSingleton() methods. LLSingletonBase::deleteAll(); + LLSplashScreen::hide(); + LL_INFOS() << "Goodbye!" << LL_ENDL; removeDumpDir(); @@ -2648,9 +2652,6 @@ void errorCallback(LLError::ELevel level, const std::string &error_string) OSMessageBox(error_display_string, caption, OSMB_OK); #endif // !LL_RELEASE_FOR_DOWNLOAD - //Set the ErrorActivated global so we know to create a marker file - gLLErrorActivated = true; - gDebugInfo["FatalMessage"] = error_string; // We're not already crashing -- we simply *intend* to crash. Since we // haven't actually trashed anything yet, we can afford to write the whole @@ -2659,6 +2660,14 @@ void errorCallback(LLError::ELevel level, const std::string &error_string) } } +void errorMSG(const std::string& title_string, const std::string& message_string) +{ + if (!message_string.empty()) + { + OSMessageBox(message_string, title_string.empty() ? LLTrans::getString("MBFatalError") : title_string, OSMB_OK); + } +} + void LLAppViewer::initLoggingAndGetLastDuration() { // @@ -2670,6 +2679,8 @@ void LLAppViewer::initLoggingAndGetLastDuration() LLError::addGenericRecorder(&errorCallback); //LLError::setTimeFunction(getRuntime); + LLError::LLUserWarningMsg::setHandler(errorMSG); + if (mSecondInstance) { @@ -2818,6 +2829,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, { // failed to load if(file.required) { + LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS() << "Error: Cannot load required settings file from: " << full_settings_path << LL_ENDL; return false; } @@ -2916,6 +2928,7 @@ bool LLAppViewer::initConfiguration() if (!success) { LL_WARNS() << "Cannot load default configuration file " << settings_file_list << LL_ENDL; + LLError::LLUserWarningMsg::showMissingFiles(); if (gDirUtilp->fileExists(settings_file_list)) { LL_ERRS() << "Cannot load default configuration file settings_files.xml. " @@ -2939,6 +2952,7 @@ bool LLAppViewer::initConfiguration() if (!mSettingsLocationList->validateBlock()) { + LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS() << "Invalid settings file list " << settings_file_list << LL_ENDL; } @@ -3468,20 +3482,19 @@ bool LLAppViewer::initConfiguration() return false; } - if (mSecondInstance) - { - // This is the second instance of SL. Turn off voice support, - // but make sure the setting is *not* persisted. - LLControlVariable* disable_voice = gSavedSettings.getControl("CmdLineDisableVoice"); - // Voice in multiple instances; by Latif Khalifa - //if(disable_voice) - if(disable_voice && !gSavedSettings.getBOOL("VoiceMultiInstance")) - // - { - const BOOL DO_NOT_PERSIST = FALSE; - disable_voice->setValue(LLSD(TRUE), DO_NOT_PERSIST); - } - } + // Voice in multiple instances + //if (mSecondInstance) + //{ + // // This is the second instance of SL. Mute voice, + // // but make sure the setting is *not* persisted. + // LLControlVariable* enable_voice = gSavedSettings.getControl("EnableVoiceChat"); + // if(enable_voice) + // { + // const BOOL DO_NOT_PERSIST = FALSE; + // enable_voice->setValue(LLSD(FALSE), DO_NOT_PERSIST); + // } + //} + // gLastRunVersion = gSavedSettings.getString("LastRunVersion"); @@ -3496,6 +3509,8 @@ bool LLAppViewer::initConfiguration() LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key)); } + LLError::LLUserWarningMsg::setOutOfMemoryStrings(LLTrans::getString("MBOutOfMemoryTitle"), LLTrans::getString("MBOutOfMemoryErr")); + // [RLVa:KB] - Patch: RLVa-2.1.0 if (LLControlVariable* pControl = gSavedSettings.getControl(RlvSettingNames::Main)) { @@ -3548,6 +3563,7 @@ void LLAppViewer::initStrings() // initial check to make sure files are there failed gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); + LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS() << "Viewer failed to find localization and UI files." << " Please reinstall viewer from https://www.firestormviewer.org/downloads" << " and contact https://www.firestormviewer.org/support if issue persists after reinstall." << LL_ENDL; @@ -3980,7 +3996,6 @@ LLSD LLAppViewer::getViewerInfo() const //info["NET_BANDWITH"] = gSavedSettings.getF32("ThrottleBandwidthKBPS"); //info["LOD_FACTOR"] = gSavedSettings.getF32("RenderVolumeLODFactor"); //info["RENDER_QUALITY"] = (F32)gSavedSettings.getU32("RenderQualityPerformance"); - //info["GPU_SHADERS"] = gSavedSettings.getBOOL("RenderDeferred") ? "Enabled" : "Disabled"; //info["TEXTURE_MEMORY"] = gGLManager.mVRAM; // @@ -5130,6 +5145,7 @@ void LLAppViewer::loadKeyBindings() key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml"); if (!gViewerInput.loadBindingsXML(key_bindings_file)) { + LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; } } @@ -5919,6 +5935,9 @@ void LLAppViewer::idleShutdown() && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME && !logoutRequestSent()) { + gViewerWindow->setShowProgress(TRUE, !gSavedSettings.getBOOL("FSDisableLogoutScreens")); + gViewerWindow->setProgressPercent(100.f); + gViewerWindow->setProgressString(LLTrans::getString("LoggingOut")); return; } @@ -6293,6 +6312,14 @@ void LLAppViewer::forceErrorLLError() LL_ERRS() << "This is a deliberate llerror" << LL_ENDL; } +void LLAppViewer::forceErrorLLErrorMsg() +{ + LLError::LLUserWarningMsg::show("Deliberate error"); + // Note: under debug this will show a message as well, + // but release won't show anything and will quit silently + LL_ERRS() << "This is a deliberate llerror with a message" << LL_ENDL; +} + void LLAppViewer::forceErrorBreakpoint() { LL_WARNS() << "Forcing a deliberate breakpoint" << LL_ENDL; @@ -6315,9 +6342,18 @@ void LLAppViewer::forceErrorBadMemoryAccess() void LLAppViewer::forceErrorInfiniteLoop() { LL_WARNS() << "Forcing a deliberate infinite loop" << LL_ENDL; + // Loop is intentionally complicated to fool basic loop detection + LLTimer timer_total; + LLTimer timer_expiry; + const S32 report_frequency = 10; + timer_expiry.setTimerExpirySec(report_frequency); while(true) { - ; + if (timer_expiry.hasExpired()) + { + LL_INFOS() << "Infinite loop time : " << timer_total.getElapsedSeconds() << LL_ENDL; + timer_expiry.setTimerExpirySec(report_frequency); + } } return; } @@ -6328,6 +6364,13 @@ void LLAppViewer::forceErrorSoftwareException() LLTHROW(LLException("User selected Force Software Exception")); } +void LLAppViewer::forceErrorOSSpecificException() +{ + // Virtual, MacOS only + const std::string exception_text = "User selected Force OS Exception, Not implemented on this OS"; + throw std::runtime_error(exception_text); +} + void LLAppViewer::forceErrorDriverCrash() { LL_WARNS() << "Forcing a deliberate driver crash" << LL_ENDL; diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 4a4b2a0136..1eb2deffd7 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -150,10 +150,12 @@ public: // LLAppViewer testing helpers. // *NOTE: These will potentially crash the viewer. Only for debugging. virtual void forceErrorLLError(); + virtual void forceErrorLLErrorMsg(); virtual void forceErrorBreakpoint(); virtual void forceErrorBadMemoryAccess(); virtual void forceErrorInfiniteLoop(); virtual void forceErrorSoftwareException(); + virtual void forceErrorOSSpecificException(); virtual void forceErrorDriverCrash(); // Wrongly merged back in by LL //virtual void forceErrorCoroutineCrash(); diff --git a/indra/newview/llappviewermacosx-objc.h b/indra/newview/llappviewermacosx-objc.h index c6dcec8e34..3721151aba 100644 --- a/indra/newview/llappviewermacosx-objc.h +++ b/indra/newview/llappviewermacosx-objc.h @@ -33,4 +33,6 @@ //Why? Because BOOL void launchApplication(const std::string* app_name, const std::vector* args); +void force_ns_sxeption(); + #endif // LL_LLAPPVIEWERMACOSX_OBJC_H diff --git a/indra/newview/llappviewermacosx-objc.mm b/indra/newview/llappviewermacosx-objc.mm index 17301847e8..5d9ca24db2 100644 --- a/indra/newview/llappviewermacosx-objc.mm +++ b/indra/newview/llappviewermacosx-objc.mm @@ -71,3 +71,9 @@ void launchApplication(const std::string* app_name, const std::vectormLODRadius; + F32 lod_radius = mRootVolp ? mRootVolp->mLODRadius : 0.f; for (std::vector::iterator it = volumes.begin(); it != volumes.end(); ++it) diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index f6e32ce260..b053094a5a 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -92,6 +92,8 @@ LLConversationItem::~LLConversationItem() { mAvatarNameCacheConnection.disconnect(); } + + clearChildren(); } //virtual @@ -256,6 +258,11 @@ LLConversationItemSession::LLConversationItemSession(const LLUUID& uuid, LLFolde mConvType = CONV_SESSION_UNKNOWN; } +LLConversationItemSession::~LLConversationItemSession() +{ + clearAndDeparentModels(); +} + bool LLConversationItemSession::hasChildren() const { return getChildrenCount() > 0; diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index 4d93f6b7ef..f3e790e9a4 100644 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -160,6 +160,7 @@ class LLConversationItemSession : public LLConversationItem public: LLConversationItemSession(std::string display_name, const LLUUID& uuid, LLFolderViewModelInterface& root_view_model); LLConversationItemSession(const LLUUID& uuid, LLFolderViewModelInterface& root_view_model); + ~LLConversationItemSession(); /*virtual*/ bool hasChildren() const; LLPointer getIcon() const { return NULL; } diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 6c92e60cf3..ce1f46464b 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -822,7 +822,7 @@ const F64Seconds LLEnvironment::TRANSITION_SLOW(10.0f); const F64Seconds LLEnvironment::TRANSITION_ALTITUDE(5.0f); const LLUUID LLEnvironment::KNOWN_SKY_SUNRISE("01e41537-ff51-2f1f-8ef7-17e4df760bfb"); -const LLUUID LLEnvironment::KNOWN_SKY_MIDDAY("651510b8-5f4d-8991-1592-e7eeab2a5a06"); +const LLUUID LLEnvironment::KNOWN_SKY_MIDDAY("c46226b4-0e43-5a56-9708-d27ca1df3292"); const LLUUID LLEnvironment::KNOWN_SKY_LEGACY_MIDDAY("cef49723-0292-af49-9b14-9598a616b8a3"); const LLUUID LLEnvironment::KNOWN_SKY_SUNSET("084e26cd-a900-28e8-08d0-64a9de5c15e2"); const LLUUID LLEnvironment::KNOWN_SKY_MIDNIGHT("8a01b97a-cb20-c1ea-ac63-f7ea84ad0090"); @@ -976,6 +976,14 @@ void LLEnvironment::initSingleton() gGenericDispatcher.addHandler(MESSAGE_PUSHENVIRONMENT, &environment_push_dispatch_handler); } + gSavedSettings.getControl("RenderSkyAutoAdjustProbeAmbiance")->getSignal()->connect( + [](LLControlVariable*, const LLSD& new_val, const LLSD& old_val) + { + LLSettingsSky::sAutoAdjustProbeAmbiance = new_val.asReal(); + } + ); + LLSettingsSky::sAutoAdjustProbeAmbiance = gSavedSettings.getF32("RenderSkyAutoAdjustProbeAmbiance"); + LLEventPumps::instance().obtain(PUMP_EXPERIENCE).stopListening(LISTENER_NAME); LLEventPumps::instance().obtain(PUMP_EXPERIENCE).listen(LISTENER_NAME, [this](LLSD message) { listenExperiencePump(message); return false; }); } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 4775686fc0..467c7e1d69 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1395,6 +1395,13 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLMaterial* mat = tep ? tep->getMaterialParams().get() : 0; // LLGLTFMaterial* gltf_mat = tep->getGLTFRenderMaterial(); + // show legacy when editing the fallback materials. + static LLCachedControl showSelectedinBP(gSavedSettings, "FSShowSelectedInBlinnPhong"); + if( gltf_mat && getViewerObject()->isSelected() && showSelectedinBP ) + { + gltf_mat = nullptr; + } + // F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index d710eafb68..71d910d9be 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -971,7 +971,7 @@ void LLFastTimerView::printLineStats() { std::string legend_stat; bool first = true; - for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != LLTrace::end_block_timer_tree_df(); ++it) { @@ -993,7 +993,7 @@ void LLFastTimerView::printLineStats() std::string timer_stat; first = true; - for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != LLTrace::end_block_timer_tree_df(); ++it) { @@ -1070,7 +1070,7 @@ void LLFastTimerView::drawLineGraph() F32Seconds cur_max(0); U32 cur_max_calls = 0; - for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != LLTrace::end_block_timer_tree_df(); ++it) { @@ -1229,8 +1229,8 @@ void LLFastTimerView::drawLegend() #pragma GCC diagnostic ignored "-Wnonnull" #endif // - for (block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != block_timer_tree_df_iterator_t(); + for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + it != LLTrace::end_block_timer_tree_df(); ++it) // GCC12 warning: nonnull - probably bogus #if defined(__GNUC__) && (__GNUC__ >= 12) @@ -1355,8 +1355,8 @@ void LLFastTimerView::generateUniqueColors() #pragma GCC diagnostic ignored "-Wnonnull" #endif // - for (block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != block_timer_tree_df_iterator_t(); + for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + it != LLTrace::end_block_timer_tree_df(); ++it) // GCC12 warning: nonnull - probably bogus #if defined(__GNUC__) && (__GNUC__ >= 12) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index ceb7a188bd..178b8f81ab 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -446,6 +446,7 @@ public: if (item) { + LLFavoritesBarCtrl::sWaitingForCallabck = 0.f; LLFavoritesOrderStorage::instance().setSortIndex(item, mSortField); item->setComplete(TRUE); @@ -491,6 +492,9 @@ struct LLFavoritesSort } }; + +F64 LLFavoritesBarCtrl::sWaitingForCallabck = 0.f; + LLFavoritesBarCtrl::Params::Params() : image_drag_indication("image_drag_indication"), more_button("more_button"), @@ -510,7 +514,7 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) mShowDragMarker(FALSE), mLandingTab(NULL), mLastTab(NULL), - mTabsHighlightEnabled(TRUE), + mItemsListDirty(false), mUpdateDropDownItems(true), mRestoreOverflowMenu(false), mGetPrevItems(true), @@ -765,6 +769,9 @@ void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, con int sortField = 0; LLPointer cb; + const F64 CALLBACK_WAIT_TIME = 30.f; + sWaitingForCallabck = LLTimer::getTotalSeconds() + CALLBACK_WAIT_TIME; + // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i) { @@ -838,16 +845,22 @@ void LLFavoritesBarCtrl::changed(U32 mask) LLFavoritesOrderStorage::instance().getSLURL((*i)->getAssetUUID()); } - updateButtons(); - if (!mItemsChangedTimer.getStarted()) - { - mItemsChangedTimer.start(); - } - else - { - mItemsChangedTimer.reset(); - } - + if (sWaitingForCallabck < LLTimer::getTotalSeconds()) + { + updateButtons(); + if (!mItemsChangedTimer.getStarted()) + { + mItemsChangedTimer.start(); + } + else + { + mItemsChangedTimer.reset(); + } + } + else + { + mItemsListDirty = true; + } } } @@ -901,6 +914,18 @@ void LLFavoritesBarCtrl::draw() mItemsChangedTimer.start(); } + if (mItemsListDirty && sWaitingForCallabck < LLTimer::getTotalSeconds()) + { + updateButtons(); + if (!mItemsChangedTimer.getStarted()) + { + mItemsChangedTimer.start(); + } + else + { + mItemsChangedTimer.reset(); + } + } } const LLButton::Params& LLFavoritesBarCtrl::getButtonParams() @@ -929,6 +954,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) return; } + mItemsListDirty = false; mItems.clear(); if (!collectFavoriteItems(mItems)) diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index a7cd5ba0a2..78e6246b84 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -56,6 +56,7 @@ public: protected: LLFavoritesBarCtrl(const Params&); friend class LLUICtrlFactory; + friend class LLItemCopiedCallback; public: virtual ~LLFavoritesBarCtrl(); @@ -87,7 +88,6 @@ protected: void onButtonRightClick(LLUUID id,LLView* button,S32 x,S32 y,MASK mask); void onButtonMouseDown(LLUUID id, LLUICtrl* button, S32 x, S32 y, MASK mask); - void onOverflowMenuItemMouseDown(LLUUID id, LLUICtrl* item, S32 x, S32 y, MASK mask); void onButtonMouseUp(LLUUID id, LLUICtrl* button, S32 x, S32 y, MASK mask); void onEndDrag(); @@ -171,7 +171,8 @@ private: BOOL mStartDrag; LLInventoryModel::item_array_t mItems; - BOOL mTabsHighlightEnabled; + static F64 sWaitingForCallabck; + bool mItemsListDirty; S32 mMouseX; S32 mMouseY; diff --git a/indra/newview/llfloaterchangeitemthumbnail.cpp b/indra/newview/llfloaterchangeitemthumbnail.cpp index 42be15ae37..7bdeff4b4d 100644 --- a/indra/newview/llfloaterchangeitemthumbnail.cpp +++ b/indra/newview/llfloaterchangeitemthumbnail.cpp @@ -752,7 +752,8 @@ void LLFloaterChangeItemThumbnail::showTexturePicker(const LLUUID &thumbnail_id) PERM_NONE, PERM_NONE, FALSE, - NULL); + NULL, + PICK_TEXTURE); mPickerHandle = floaterp->getHandle(); diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp index bb47feaa95..4e764674e5 100644 --- a/indra/newview/llfloatereditextdaycycle.cpp +++ b/indra/newview/llfloatereditextdaycycle.cpp @@ -1724,7 +1724,9 @@ void LLFloaterEditExtDayCycle::showHDRNotification(const LLSettingsDay::ptr_t &p while (iter != end) { LLSettingsSky::ptr_t sky = std::static_pointer_cast(iter->second); - if (sky && sky->canAutoAdjust()) + if (sky + && sky->canAutoAdjust() + && sky->getReflectionProbeAmbiance(true) != 0.f) { LLNotificationsUtil::add("AutoAdjustHDRSky"); return; diff --git a/indra/newview/llfloaterenvironmentadjust.cpp b/indra/newview/llfloaterenvironmentadjust.cpp index c64ee5a69c..c98afefa65 100644 --- a/indra/newview/llfloaterenvironmentadjust.cpp +++ b/indra/newview/llfloaterenvironmentadjust.cpp @@ -116,7 +116,7 @@ BOOL LLFloaterEnvironmentAdjust::postBuild() getChild(FIELD_SKY_CLOUD_MAP)->setAllowNoTexture(TRUE); getChild(FIELD_WATER_NORMAL_MAP)->setDefaultImageAssetID(LLSettingsWater::GetDefaultWaterNormalAssetId()); - getChild(FIELD_WATER_NORMAL_MAP)->setBlankImageAssetID(LLUUID(gSavedSettings.getString("DefaultBlankNormalTexture"))); + getChild(FIELD_WATER_NORMAL_MAP)->setBlankImageAssetID(BLANK_OBJECT_NORMAL); getChild(FIELD_WATER_NORMAL_MAP)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onWaterMapChanged(); }); getChild(FIELD_REFLECTION_PROBE_AMBIANCE)->setCommitCallback([this](LLUICtrl*, const LLSD&) { onReflectionProbeAmbianceChanged(); }); diff --git a/indra/newview/llfloaterfixedenvironment.cpp b/indra/newview/llfloaterfixedenvironment.cpp index 8e28fd6234..3e8bad3ef5 100644 --- a/indra/newview/llfloaterfixedenvironment.cpp +++ b/indra/newview/llfloaterfixedenvironment.cpp @@ -186,7 +186,8 @@ void LLFloaterFixedEnvironment::setEditSettingsAndUpdate(const LLSettingsBase::p // teach user about HDR settings if (mSettings && mSettings->getSettingsType() == "sky" - && ((LLSettingsSky*)mSettings.get())->canAutoAdjust()) + && ((LLSettingsSky*)mSettings.get())->canAutoAdjust() + && ((LLSettingsSky*)mSettings.get())->getReflectionProbeAmbiance(true) != 0.f) { LLNotificationsUtil::add("AutoAdjustHDRSky"); } diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index a070645bdf..9ac7c74746 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -1782,6 +1782,7 @@ void LLFloaterIMContainer::setTimeNow(const LLUUID& session_id, const LLUUID& pa LLConversationItemSession* item = dynamic_cast(getSessionModel(session_id)); if (item) { + item->setTimeNow(participant_id); mConversationViewModel.requestSortAll(); mConversationsRoot->arrangeAll(); } diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 2031fc6a4e..2f3d75d123 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -619,6 +619,8 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, static LLCachedControl FSllOwnerSayToScriptDebugWindow(gSavedPerAccountSettings, "FSllOwnerSayToScriptDebugWindow"); if (chat_msg.mChatType == CHAT_TYPE_DEBUG_MSG || (chat_msg.mChatType == CHAT_TYPE_OWNER && FSllOwnerSayToScriptDebugWindow)) { + if (LLFloater::isQuitRequested()) return; + // [FSllOwnerSayToScriptDebugWindow] Show llOwnerSays in the script debug window instead of local chat // if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE) if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE && chat_msg.mChatType == CHAT_TYPE_DEBUG_MSG) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index ed1080eda9..bddec16b09 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -126,6 +126,7 @@ #include "llpresetsmanager.h" #include "llviewercontrol.h" #include "llpresetsmanager.h" +#include "llinventoryfunctions.h" #include "llsearchableui.h" #include "llperfstats.h" @@ -2839,25 +2840,6 @@ void LLFloaterPreference::onChangeMaturity() getChild("rating_icon_adult")->setVisible(sim_access == SIM_ACCESS_ADULT); } -std::string get_category_path(LLUUID cat_id) -{ - LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); - std::string localized_cat_name; - if (!LLTrans::findString(localized_cat_name, "InvFolder " + cat->getName())) - { - localized_cat_name = cat->getName(); - } - - if (cat->getParentUUID().notNull()) - { - return get_category_path(cat->getParentUUID()) + " > " + localized_cat_name; - } - else - { - return localized_cat_name; - } -} - std::string get_category_path(LLFolderType::EType cat_type) { LLUUID cat_id = gInventory.findUserDefinedCategoryUUIDForType(cat_type); diff --git a/indra/newview/llfloaterprofiletexture.cpp b/indra/newview/llfloaterprofiletexture.cpp index 94340eb36f..5fc0ea55ea 100644 --- a/indra/newview/llfloaterprofiletexture.cpp +++ b/indra/newview/llfloaterprofiletexture.cpp @@ -60,6 +60,8 @@ LLFloaterProfileTexture::~LLFloaterProfileTexture() mImage->forceActive(); // Make sure it can get discarded mImage = NULL; } + + LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList); } // virtual diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 33d18f7f23..9951fbdbff 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -151,7 +151,7 @@ public: const LLUUID& invoice, const sparam_t& strings); - LLSD getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count ); + static LLSD getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count ); }; @@ -2686,11 +2686,12 @@ bool LLDispatchSetEstateAccess::operator()( return true; } +// static LLSD LLDispatchSetEstateExperience::getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count ) { LLSD idList = LLSD::emptyArray(); LLUUID id; - while(count--> 0) + while (count-- > 0 && it < end) { memcpy(id.mData, (*(it++)).data(), UUID_BYTES); idList.append(id); @@ -2704,7 +2705,7 @@ LLSD LLDispatchSetEstateExperience::getIDs( sparam_t::const_iterator it, sparam_ // strings[2] = str(num blocked) // strings[3] = str(num trusted) // strings[4] = str(num allowed) -// strings[8] = bin(uuid) ... +// strings[5] = bin(uuid) ... // ... bool LLDispatchSetEstateExperience::operator()( const LLDispatcher* dispatcher, @@ -2713,23 +2714,30 @@ bool LLDispatchSetEstateExperience::operator()( const sparam_t& strings) { LLPanelRegionExperiences* panel = LLFloaterRegionInfo::getPanelExperiences(); - if (!panel) return true; + if (!panel) + return true; + const sparam_t::size_type MIN_SIZE = 5; + if (strings.size() < MIN_SIZE) + return true; + + // Skip 2 parameters sparam_t::const_iterator it = strings.begin(); ++it; // U32 estate_id = strtol((*it).c_str(), NULL, 10); ++it; // U32 send_to_agent_only = strtoul((*(++it)).c_str(), NULL, 10); + // Read 3 parameters LLUUID id; S32 num_blocked = strtol((*(it++)).c_str(), NULL, 10); S32 num_trusted = strtol((*(it++)).c_str(), NULL, 10); S32 num_allowed = strtol((*(it++)).c_str(), NULL, 10); LLSD ids = LLSD::emptyMap() - .with("blocked", getIDs(it, strings.end(), num_blocked)) - .with("trusted", getIDs(it + (num_blocked), strings.end(), num_trusted)) - .with("allowed", getIDs(it + (num_blocked+num_trusted), strings.end(), num_allowed)); + .with("blocked", getIDs(it, strings.end(), num_blocked)) + .with("trusted", getIDs(it + num_blocked, strings.end(), num_trusted)) + .with("allowed", getIDs(it + num_blocked + num_trusted, strings.end(), num_allowed)); - panel->processResponse(ids); + panel->processResponse(ids); return true; } diff --git a/indra/newview/llfloatersidepanelcontainer.cpp b/indra/newview/llfloatersidepanelcontainer.cpp index e744eba5ea..38477be80c 100644 --- a/indra/newview/llfloatersidepanelcontainer.cpp +++ b/indra/newview/llfloatersidepanelcontainer.cpp @@ -71,14 +71,14 @@ void LLFloaterSidePanelContainer::closeFloater(bool app_quitting) if (parent == this ) { LLSidepanelAppearance* panel_appearance = dynamic_cast(getPanel("appearance")); - if ( panel_appearance ) + if (panel_appearance) { LLPanelEditWearable *edit_wearable_ptr = panel_appearance->getWearable(); if (edit_wearable_ptr) { edit_wearable_ptr->onClose(); } - if(!app_quitting) + if (!app_quitting) { panel_appearance->showOutfitsInventoryPanel(); } @@ -133,11 +133,16 @@ LLFloater* LLFloaterSidePanelContainer::getTopmostInventoryFloater() LLPanel* LLFloaterSidePanelContainer::openChildPanel(const std::string& panel_name, const LLSD& params) { LLView* view = findChildView(panel_name, true); - if (!view) return NULL; + if (!view) + return NULL; if (!getVisible()) { - openFloater(); + openFloater(); + } + else if (!hasFocus()) + { + setFocus(TRUE); } LLPanel* panel = NULL; diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index d765327925..ef5b19ba2d 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -94,6 +94,8 @@ #include "llvograss.h" #include "llvotree.h" +#include "fspanelface.h" // switchable edit texture/materials panel + // Globals LLFloaterTools *gFloaterTools = NULL; bool LLFloaterTools::sShowObjectCost = true; @@ -174,8 +176,14 @@ void* LLFloaterTools::createPanelVolume(void* data) void* LLFloaterTools::createPanelFace(void* data) { LLFloaterTools* floater = (LLFloaterTools*)data; - floater->mPanelFace = new LLPanelFace(); - return floater->mPanelFace; + + // switchable edit texture/materials panel + // we should not need this here at all, we are adding the texture/materials + // panel in postBuild() + // floater->mPanelFace = new LLPanelFace(); + // return floater->mPanelFace; + return floater->findChild("Texture"); + // } //static @@ -229,6 +237,27 @@ LLPCode toolData[]={ BOOL LLFloaterTools::postBuild() { + // switchable edit texture/materials panel + LLPanel* panel; + if (gSavedSettings.getBOOL("FSUseNewTexturePanel")) + { + mFSPanelFace = new FSPanelFace; + panel = mFSPanelFace; + } + else + { + mPanelFace = new LLPanelFace; + panel = mPanelFace; + } + + LLTabContainer::TabPanelParams params; + params.panel = panel; + params.insert_at = (LLTabContainer::eInsertionPoint) PANEL_FACE; + + mTab = getChild("Object Info Tabs"); + mTab->addTabPanel(params); + // + // Hide until tool selected setVisible(FALSE); @@ -367,7 +396,11 @@ void LLFloaterTools::changePrecision(S32 decimal_precision) else if (decimal_precision > 7) decimal_precision = 7; mPanelObject->changePrecision(decimal_precision); - mPanelFace->changePrecision(decimal_precision); + // switchable edit texture/materials panel + // mPanelFace->changePrecision(decimal_precision); + if (mPanelFace) mPanelFace->changePrecision(decimal_precision); + if (mFSPanelFace) mFSPanelFace->changePrecision(decimal_precision); + // } // Create the popupview with a dummy center. It will be moved into place @@ -431,6 +464,7 @@ LLFloaterTools::LLFloaterTools(const LLSD& key) mPanelVolume(NULL), mPanelContents(NULL), mPanelFace(NULL), + mFSPanelFace(nullptr), // switchable edit texture/materials panel mPanelLandInfo(NULL), mCostTextBorder(NULL), @@ -470,7 +504,6 @@ LLFloaterTools::LLFloaterTools(const LLSD& key) // mCommitCallbackRegistrar.add("BuildTool.CopyKeys", boost::bind(&LLFloaterTools::onClickBtnCopyKeys,this)); mCommitCallbackRegistrar.add("BuildTool.Expand", boost::bind(&LLFloaterTools::onClickExpand,this)); - mCommitCallbackRegistrar.add("BuildTool.Flip", boost::bind(&LLPanelFace::onCommitFlip, _1, _2)); // // FIRE-7802: Grass and tree selection in build tool @@ -744,8 +777,20 @@ void LLFloaterTools::refresh() mPanelPermissions->refresh(); mPanelObject->refresh(); mPanelVolume->refresh(); - mPanelFace->refresh(); - mPanelFace->refreshMedia(); + // switchable edit texture/materials panel + // mPanelFace->refresh(); + // mPanelFace->refreshMedia(); + if (mPanelFace) + { + mPanelFace->refresh(); + mPanelFace->refreshMedia(); + } + if (mFSPanelFace) + { + mFSPanelFace->refresh(); + mFSPanelFace->refreshMedia(); + } + // mPanelContents->refresh(); mPanelLandInfo->refresh(); @@ -1142,7 +1187,11 @@ void LLFloaterTools::onClose(bool app_quitting) LLViewerJoystick::getInstance()->moveAvatar(false); // destroy media source used to grab media title - mPanelFace->unloadMedia(); + // switchable edit texture/materials panel + // mPanelFace->unloadMedia(); + if (mPanelFace) mPanelFace->unloadMedia(); + if (mFSPanelFace) mFSPanelFace->unloadMedia(); + // // Different from handle_reset_view in that it doesn't actually // move the camera if EditCameraMovement is not set. @@ -1626,3 +1675,39 @@ void LLFloaterTools::onSelectTreeGrassCombo() } } // + +// switchable edit texture/materials panel +void LLFloaterTools::refreshPanelFace() +{ + if (mPanelFace) mPanelFace->refresh(); + if (mFSPanelFace) mFSPanelFace->refresh(); +} + +LLRender::eTexIndex LLFloaterTools::getTextureDropChannel() +{ + if (mPanelFace) return mPanelFace->getTextureDropChannel(); + if (mFSPanelFace) return mFSPanelFace->getTextureDropChannel(); + return LLRender::NUM_TEXTURE_CHANNELS; // invalid +} + +LLRender::eTexIndex LLFloaterTools::getTextureChannelToEdit() +{ + if (mPanelFace) return mPanelFace->getTextureChannelToEdit(); + if (mFSPanelFace) return mFSPanelFace->getTextureChannelToEdit(); + return LLRender::NUM_TEXTURE_CHANNELS; // invalid +} + +LLGLTFMaterial::TextureInfo LLFloaterTools::getPBRDropChannel() +{ + if (mPanelFace) return mPanelFace->getPBRDropChannel(); + if (mFSPanelFace) return mFSPanelFace->getPBRDropChannel(); + return LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; // invalid +} + +LLMaterialPtr LLFloaterTools::createDefaultMaterial(LLMaterialPtr old_mat) +{ + if (mPanelFace) return mPanelFace->createDefaultMaterial(old_mat); + if (mFSPanelFace) return mFSPanelFace->createDefaultMaterial(old_mat); + return nullptr; // invalid +} +// diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index eec968d815..2ea5daaf93 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -50,6 +50,14 @@ class LLParcelSelection; class LLObjectSelection; class LLLandImpactsObserver; +// switchable edit texture/materials panel +#include "llgltfmaterial.h" +#include "llmaterial.h" +#include "llrender.h" + +class FSPanelFace; +// + typedef LLSafeHandle LLObjectSelectionHandle; class LLFloaterTools @@ -107,7 +115,14 @@ public: static void setGridMode(S32 mode); - LLPanelFace* getPanelFace() { return mPanelFace; } + // switchable edit texture/materials panel + // LLPanelFace* getPanelFace() { return mPanelFace; } + LLRender::eTexIndex getTextureDropChannel(); + LLRender::eTexIndex getTextureChannelToEdit(); + LLGLTFMaterial::TextureInfo getPBRDropChannel(); + LLMaterialPtr createDefaultMaterial(LLMaterialPtr old_mat); + void refreshPanelFace(); + // void onClickBtnCopyKeys(); void onClickExpand(); @@ -193,7 +208,7 @@ public: LLPanelObject *mPanelObject; LLPanelVolume *mPanelVolume; LLPanelContents *mPanelContents; - LLPanelFace *mPanelFace; +// LLPanelFace *mPanelFace; // switchable edit texture/materials panel LLPanelLandInfo *mPanelLandInfo; LLViewBorder* mCostTextBorder; @@ -215,6 +230,9 @@ private: S32 mExpandedHeight; std::map mStatusText; + LLPanelFace* mPanelFace; // switchable edit texture/materials panel + FSPanelFace* mFSPanelFace; // switchable edit texture/materials panel + public: static bool sShowObjectCost; static bool sPreviousFocusOnAvatar; diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp index 8919229c78..b7022ac69c 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -139,69 +139,18 @@ static bool is_valid_update(const LLSD& data) } #endif -class LLGLTFMaterialOverrideDispatchHandler : public LLDispatchHandler +class LLGLTFMaterialOverrideDispatchHandler { LOG_CLASS(LLGLTFMaterialOverrideDispatchHandler); public: LLGLTFMaterialOverrideDispatchHandler() = default; - ~LLGLTFMaterialOverrideDispatchHandler() override = default; + ~LLGLTFMaterialOverrideDispatchHandler() = default; void addCallback(void(*callback)(const LLUUID& object_id, S32 side)) { mSelectionCallbacks.push_back(callback); } - bool operator()(const LLDispatcher* dispatcher, const std::string& key, const LLUUID& invoice, const sparam_t& strings) override - { - LL_PROFILE_ZONE_SCOPED; - // receive override data from simulator via LargeGenericMessage - // message should have: - // object_id - UUID of LLViewerObject - // sides - array of S32 indices of texture entries - // gltf_json - array of corresponding Strings of GLTF json for override data - - LLSD message; - bool success = true; -#if 0 //deprecated - for(const std::string& llsdRaw : strings) - { - std::istringstream llsdData(llsdRaw); - if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length())) - { - LL_WARNS() << "LLGLTFMaterialOverrideDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; - success = false; - continue; - } - - LLGLTFOverrideCacheEntry object_override; - if (!object_override.fromLLSD(message)) - { - // malformed message, nothing we can do to handle it - LL_DEBUGS("GLTF") << "Message without id:" << message << LL_ENDL; - success = false; - continue; - } - - // Cache the data - { - LLViewerRegion * region = LLWorld::instance().getRegionFromHandle(object_override.mRegionHandle); - - if (region) - { - region->cacheFullUpdateGLTFOverride(object_override); - } - else - { - LL_WARNS("GLTF") << "could not access region for material overrides message cache, region_handle: " << LL_ENDL; - } - } - applyData(object_override); - } - -#endif - return success; - } - void doSelectionCallbacks(const LLUUID& object_id, S32 side) { for (auto& callback : mSelectionCallbacks) @@ -210,112 +159,6 @@ public: } } - void applyData(const LLGLTFOverrideCacheEntry &object_override) - { - // Parse the data - -#if 0 // DEPRECATED - LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop"); - LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General"); - - struct ReturnData - { - public: - LLGLTFMaterial mMaterial; - S32 mSide; - bool mSuccess; - }; - - if (!object_override.mSides.empty()) - { - // fromJson() is performance heavy offload to a thread. - main_queue->postTo( - general_queue, - [sides=object_override.mSides]() // Work done on general queue - { - std::vector results; - - results.reserve(sides.size()); - // parse json - std::unordered_map::const_iterator iter = sides.begin(); - std::unordered_map::const_iterator end = sides.end(); - while (iter != end) - { - ReturnData result; - - result.mMaterial.applyOverrideLLSD(iter->second); - - result.mSuccess = true; - result.mSide = iter->first; - - results.push_back(result); - iter++; - } - return results; - }, - [object_id=object_override.mObjectId, this](std::vector results) // Callback to main thread - { - LLViewerObject * obj = gObjectList.findObject(object_id); - - if (results.size() > 0 ) - { - std::unordered_set side_set; - - for (auto const & result : results) - { - S32 side = result.mSide; - if (result.mSuccess) - { - // copy to heap here because LLTextureEntry is going to take ownership with an LLPointer - LLGLTFMaterial * material = new LLGLTFMaterial(result.mMaterial); - - // flag this side to not be nulled out later - side_set.insert(side); - - if (obj) - { - obj->setTEGLTFMaterialOverride(side, material); - } - } - - // unblock material editor - if (obj && obj->getTE(side) && obj->getTE(side)->isSelected()) - { - doSelectionCallbacks(object_id, side); - } - } - - if (obj && side_set.size() != obj->getNumTEs()) - { // object exists and at least one texture entry needs to have its override data nulled out - for (int i = 0; i < obj->getNumTEs(); ++i) - { - if (side_set.find(i) == side_set.end()) - { - obj->setTEGLTFMaterialOverride(i, nullptr); - if (obj->getTE(i) && obj->getTE(i)->isSelected()) - { - doSelectionCallbacks(object_id, i); - } - } - } - } - } - else if (obj) - { // override list was empty or an error occurred, null out all overrides for this object - for (int i = 0; i < obj->getNumTEs(); ++i) - { - obj->setTEGLTFMaterialOverride(i, nullptr); - if (obj->getTE(i) && obj->getTE(i)->isSelected()) - { - doSelectionCallbacks(obj->getID(), i); - } - } - } - }); - } -#endif - } - private: std::vector mSelectionCallbacks; @@ -402,8 +245,13 @@ void LLGLTFMaterialList::applyOverrideMessage(LLMessageSystem* msg, const std::s } } } - - region->cacheFullUpdateGLTFOverride(cache); + // FIRE-33808 - Material Override Cache causes long delays + if(cache.mSides.size() > 0) + { + region->cacheFullUpdateGLTFOverride(cache); + LL_DEBUGS("GLTF") << "GLTF Material Override: " << cache.mObjectId << " " << cache.mLocalId << " " << cache.mRegionHandle << " (sides:" << (cache.mSides.size()) << ")" << LL_ENDL; + } + // } } @@ -821,12 +669,6 @@ void LLGLTFMaterialList::flushMaterials() } } -// static -void LLGLTFMaterialList::registerCallbacks() -{ - gGenericDispatcher.addHandler("GLTFMaterialOverride", &handle_gltf_override_message); -} - // static void LLGLTFMaterialList::modifyMaterialCoro(std::string cap_url, LLSD overrides, void(*done_callback)(bool) ) { @@ -864,7 +706,3 @@ void LLGLTFMaterialList::modifyMaterialCoro(std::string cap_url, LLSD overrides, } } -void LLGLTFMaterialList::loadCacheOverrides(const LLGLTFOverrideCacheEntry& override) -{ - handle_gltf_override_message.applyData(override); -} diff --git a/indra/newview/llgltfmateriallist.h b/indra/newview/llgltfmateriallist.h index 7317214019..f1c4ce20f9 100644 --- a/indra/newview/llgltfmateriallist.h +++ b/indra/newview/llgltfmateriallist.h @@ -52,8 +52,6 @@ public: void flushMaterials(); - static void registerCallbacks(); - // Queue an modification of a material that we want to send to the simulator. Call "flushUpdates" to flush pending updates. // id - ID of object to modify // side - TexureEntry index to modify, or -1 for all sides @@ -99,8 +97,6 @@ public: // any override data that arrived before the object was ready to receive it void applyQueuedOverrides(LLViewerObject* obj); - static void loadCacheOverrides(const LLGLTFOverrideCacheEntry& override); - // Apply an override update with the given data void applyOverrideMessage(LLMessageSystem* msg, const std::string& data); diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp index a5e701b831..fc648d38ba 100644 --- a/indra/newview/llhudnametag.cpp +++ b/indra/newview/llhudnametag.cpp @@ -907,6 +907,15 @@ void LLHUDNameTag::shift(const LLVector3& offset) mPositionAgent += offset; } +F32 LLHUDNameTag::getWorldHeight() const +{ + const LLViewerCamera* camera = LLViewerCamera::getInstance(); + F32 height_meters = mLastDistance * (F32)tan(camera->getView() / 2.f); + F32 height_pixels = camera->getViewHeightInPixels() / 2.f; + F32 meters_per_pixel = height_meters / height_pixels; + return mHeight * meters_per_pixel * gViewerWindow->getDisplayScale().mV[VY]; +} + //static void LLHUDNameTag::addPickable(std::set &pick_list) { diff --git a/indra/newview/llhudnametag.h b/indra/newview/llhudnametag.h index 361e4d4f4b..592ab5518f 100644 --- a/indra/newview/llhudnametag.h +++ b/indra/newview/llhudnametag.h @@ -127,11 +127,12 @@ public: /*virtual*/ void markDead(); friend class LLHUDObject; /*virtual*/ F32 getDistance() const { return mLastDistance; } - S32 getLOD() { return mLOD; } - BOOL getVisible() { return mVisible; } + S32 getLOD() const { return mLOD; } + BOOL getVisible() const { return mVisible; } BOOL getHidden() const { return mHidden; } void setHidden( BOOL hide ) { mHidden = hide; } void shift(const LLVector3& offset); + F32 getWorldHeight() const; BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a& intersection, BOOL debug_render = FALSE); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index e94aadfb85..ec523d7aff 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1929,7 +1929,7 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) } else if ("show_in_main_panel" == action) { - LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, mUUID, TRUE); + LLInventoryPanel::openInventoryPanelAndSetSelection(true, mUUID, true); return; } else if ("cut" == action) @@ -3719,7 +3719,7 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) // else if ("show_in_main_panel" == action) { - LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, mUUID, TRUE); + LLInventoryPanel::openInventoryPanelAndSetSelection(true, mUUID, true); return; } else if ("cut" == action) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 8bd64a6406..8ca337d4bf 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2282,6 +2282,24 @@ void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::st gInventory.createNewCategory(first_item->getParentUUID(), LLFolderType::FT_NONE, folder_name, func); } +std::string get_category_path(LLUUID cat_id) +{ + LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + std::string localized_cat_name; + if (!LLTrans::findString(localized_cat_name, "InvFolder " + cat->getName())) + { + localized_cat_name = cat->getName(); + } + + if (cat->getParentUUID().notNull()) + { + return get_category_path(cat->getParentUUID()) + " > " + localized_cat_name; + } + else + { + return localized_cat_name; + } +} // Returns true if the item can be moved to Current Outfit or any outfit folder. bool can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit) { @@ -2708,6 +2726,12 @@ bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item return FALSE; } +bool LLAssetIDAndTypeMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + if (!item) return false; + return (item->getActualType() == mType && item->getAssetUUID() == mAssetID); +} + bool LLIsValidItemLink::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { LLViewerInventoryItem *vitem = dynamic_cast(item); diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index db10b7288e..6d77c8a48d 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -113,6 +113,7 @@ void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::st void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids); bool is_only_cats_selected(const uuid_vec_t& selected_uuids); bool is_only_items_selected(const uuid_vec_t& selected_uuids); +std::string get_category_path(LLUUID cat_id); bool can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit); bool can_move_to_landmarks(LLInventoryItem* inv_item); @@ -285,6 +286,28 @@ protected: LLAssetType::EType mType; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLAssetIDAndTypeMatches +// +// Implementation of a LLInventoryCollectFunctor which returns TRUE if +// the item matches both asset type and asset id. +// This is needed in case you are looking for a specific type with default id +// (since null is default for multiple asset types) +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLAssetIDAndTypeMatches: public LLInventoryCollectFunctor +{ +public: + LLAssetIDAndTypeMatches(const LLUUID& asset_id, LLAssetType::EType type): mAssetID(asset_id), mType(type) {} + virtual ~LLAssetIDAndTypeMatches() {} + bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + +protected: + LLUUID mAssetID; + LLAssetType::EType mType; +}; + class LLIsValidItemLink : public LLInventoryCollectFunctor { public: diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp index 23129f7d44..cac859387c 100644 --- a/indra/newview/llinventoryitemslist.cpp +++ b/indra/newview/llinventoryitemslist.cpp @@ -240,7 +240,7 @@ void LLInventoryItemsList::refresh() case REFRESH_LIST_SORT: { // Filter, sort, rearrange and notify parent about shape changes - filterItems(); + filterItems(true, true); if (mAddedItems.size() == 0) { diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h index ce41105f98..5b83298bb9 100644 --- a/indra/newview/llinventoryitemslist.h +++ b/indra/newview/llinventoryitemslist.h @@ -51,20 +51,20 @@ public: /** * Let list know items need to be refreshed in next doIdle() */ - void setNeedsRefresh(bool needs_refresh){ mRefreshState = needs_refresh ? REFRESH_ALL : REFRESH_COMPLETE; } + void setNeedsRefresh(bool needs_refresh) { mRefreshState = needs_refresh ? REFRESH_ALL : REFRESH_COMPLETE; } - U32 getNeedsRefresh(){ return mRefreshState; } + U32 getNeedsRefresh() { return mRefreshState; } /** * Sets the flag indicating that the list needs to be refreshed even if it is * not currently visible. */ - void setForceRefresh(bool force_refresh){ mForceRefresh = force_refresh; } + void setForceRefresh(bool force_refresh) { mForceRefresh = force_refresh; } /** * If refreshes when invisible. */ - bool getForceRefresh(){ return mForceRefresh; } + bool getForceRefresh() { return mForceRefresh; } virtual bool selectItemByValue(const LLSD& value, bool select = true); diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index de30b31076..0893c9c04e 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -603,8 +603,12 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask) for (uuid_set_t::iterator it = added.begin(); it != added.end(); ++it) { LLInventoryItem *item = gInventory.getItem(*it); + if (!item) + { + continue; + } const LLUUID& asset_uuid = item->getAssetUUID(); - if (item && item->getUUID().notNull() && asset_uuid.notNull()) + if (item->getUUID().notNull() && asset_uuid.notNull()) { if (isAssetWatched(asset_uuid)) { diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index c71eb8573b..2662facf35 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -2154,62 +2154,68 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open) } //static -void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id, BOOL use_main_panel, BOOL take_keyboard_focus, BOOL reset_filter) +void LLInventoryPanel::openInventoryPanelAndSetSelection(bool auto_open, const LLUUID& obj_id, + bool use_main_panel, bool take_keyboard_focus, bool reset_filter) { // Use correct inventory floater //LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel("inventory"); //sidepanel_inventory->showInventoryPanel(); // - bool in_inbox = (gInventory.isObjectDescendentOf(obj_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX))); + LLUUID cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); + bool in_inbox = gInventory.isObjectDescendentOf(obj_id, cat_id); bool show_inbox = gSavedSettings.getBOOL("FSShowInboxFolder"); // Optional hiding of Received Items folder aka Inbox - // FIRE-22167: Make "Show in Main View" work properly - //if (!in_inbox && (use_main_panel || !sidepanel_inventory->getMainInventoryPanel()->isRecentItemsPanelSelected())) //if (main_panel && !in_inbox) + //if (!in_inbox && use_main_panel) //{ // sidepanel_inventory->selectAllItemsPanel(); //} // - - LLFloater* inventory_floater = LLFloaterSidePanelContainer::getTopmostInventoryFloater(); - if(!auto_open && inventory_floater && inventory_floater->getVisible()) + if (!auto_open) { - LLSidepanelInventory *inventory_panel = inventory_floater->findChild("main_panel"); - LLPanelMainInventory* main_panel = inventory_panel->getMainInventoryPanel(); - if(main_panel->isSingleFolderMode() && main_panel->isGalleryViewMode()) + LLFloater* inventory_floater = LLFloaterSidePanelContainer::getTopmostInventoryFloater(); + if (inventory_floater && inventory_floater->getVisible()) { - LL_DEBUGS("Inventory") << "Opening gallery panel for item" << obj_id << LL_ENDL; - main_panel->setGallerySelection(obj_id); - return; + LLSidepanelInventory *inventory_panel = inventory_floater->findChild("main_panel"); + LLPanelMainInventory* main_panel = inventory_panel->getMainInventoryPanel(); + if (main_panel->isSingleFolderMode() && main_panel->isGalleryViewMode()) + { + LL_DEBUGS("Inventory") << "Opening gallery panel for item" << obj_id << LL_ENDL; + main_panel->setGallerySelection(obj_id); + return; + } } } - // Use correct inventory floater - //LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); - //if (main_inventory && main_inventory->isSingleFolderMode() - // && use_main_panel) + // Use correct inventory floater + //if (use_main_panel) //{ - // const LLInventoryObject *obj = gInventory.getObject(obj_id); - // if (obj) + // LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); + // if (main_inventory && main_inventory->isSingleFolderMode()) // { - // LL_DEBUGS("Inventory") << "Opening main inventory panel for item" << obj_id << LL_ENDL; - // main_inventory->setSingleFolderViewRoot(obj->getParentUUID(), false); - // main_inventory->setGallerySelection(obj_id); - // return; + // const LLInventoryObject *obj = gInventory.getObject(obj_id); + // if (obj) + // { + // LL_DEBUGS("Inventory") << "Opening main inventory panel for item" << obj_id << LL_ENDL; + // main_inventory->setSingleFolderViewRoot(obj->getParentUUID(), false); + // main_inventory->setGallerySelection(obj_id); + // return; + // } // } //} - if (!inventory_floater) + LLFloater* inv_floater = LLFloaterSidePanelContainer::getTopmostInventoryFloater(); + if (!inv_floater) { - inventory_floater = LLFloaterReg::showInstance("inventory"); + inv_floater = LLFloaterReg::showInstance("inventory"); } - if (use_main_panel && inventory_floater) + if (use_main_panel && inv_floater) { - LLSidepanelInventory* inventory_panel = inventory_floater->findChild("main_panel"); + LLSidepanelInventory* inventory_panel = inv_floater->findChild("main_panel"); LLPanelMainInventory* main_inventory = inventory_panel->getMainInventoryPanel(); if (main_inventory && main_inventory->isSingleFolderMode()) { - const LLInventoryObject *obj = gInventory.getObject(obj_id); + const LLInventoryObject* obj = gInventory.getObject(obj_id); if (obj) { main_inventory->setSingleFolderViewRoot(obj->getParentUUID(), false); @@ -2221,7 +2227,6 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L // LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open); - if (active_panel) { LL_DEBUGS("Messaging", "Inventory") << "Highlighting" << obj_id << LL_ENDL; @@ -2237,10 +2242,8 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L // { LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel("inventory"); // Use correct inventory floater - LLInventoryPanel * inventory_panel = NULL; sidepanel_inventory->openInbox(); - inventory_panel = sidepanel_inventory->getInboxPanel(); - + LLInventoryPanel* inventory_panel = sidepanel_inventory->getInboxPanel(); if (inventory_panel) { inventory_panel->setSelection(obj_id, take_keyboard_focus); @@ -2273,7 +2276,6 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L void LLInventoryPanel::setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id) { - LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) { diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 06f08fda5c..aefb8482cb 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -260,12 +260,12 @@ public: // "Auto_open" determines if we open an inventory panel if none are open. static LLInventoryPanel *getActiveInventoryPanel(BOOL auto_open = TRUE); - static void openInventoryPanelAndSetSelection(BOOL auto_open, + static void openInventoryPanelAndSetSelection(bool auto_open, const LLUUID& obj_id, - BOOL use_main_panel = FALSE, - BOOL take_keyboard_focus = TAKE_FOCUS_YES, - BOOL reset_filter = FALSE); - static void setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id); + bool use_main_panel = false, + bool take_keyboard_focus = true, + bool reset_filter = false); + static void setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id); void addItemID(const LLUUID& id, LLFolderViewItem* itemp); void removeItemID(const LLUUID& id); LLFolderViewItem* getItemByID(const LLUUID& id); diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index d1938d62f6..9e22d73845 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -1090,6 +1090,13 @@ bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename) LLImageDimensionsInfo image_info; if (!image_info.load(filename,codec)) { + LLSD args; + args["NAME"] = gDirUtilp->getBaseFileName(filename); + if (!image_info.getWarningName().empty()) + { + args["REASON"] = LLTrans::getString(image_info.getWarningName()); + } + LLNotificationsUtil::add("CannotUploadTexture", args); return false; } @@ -1105,6 +1112,7 @@ bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename) LLSD notif_args; notif_args["REASON"] = mImageLoadError; + notif_args["NAME"] = gDirUtilp->getBaseFileName(filename); LLNotificationsUtil::add("CannotUploadTexture", notif_args); return false; diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 9f696f2787..97902aa64f 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -43,6 +43,7 @@ #include "llnotificationsutil.h" #include "lltexturectrl.h" #include "lltrans.h" +#include "llviewercontrol.h" #include "llviewermenufile.h" #include "llviewertexture.h" #include "llsdutil.h" @@ -451,6 +452,8 @@ BOOL LLMaterialEditor::postBuild() mEmissiveTextureCtrl->setCommitCallback(boost::bind(&LLMaterialEditor::onCommitTexture, this, _1, _2, MATERIAL_EMISIVE_TEX_DIRTY)); mNormalTextureCtrl->setCommitCallback(boost::bind(&LLMaterialEditor::onCommitTexture, this, _1, _2, MATERIAL_NORMAL_TEX_DIRTY)); + mNormalTextureCtrl->setBlankImageAssetID(BLANK_OBJECT_NORMAL); + if (mIsOverride) { // Live editing needs a recovery mechanism on cancel @@ -1379,10 +1382,23 @@ bool LLMaterialEditor::saveIfNeeded() LLPermissions local_permissions; local_permissions.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); - U32 everyone_perm = LLFloaterPerms::getEveryonePerms("Materials"); - U32 group_perm = LLFloaterPerms::getGroupPerms("Materials"); - U32 next_owner_perm = LLFloaterPerms::getNextOwnerPerms("Materials"); - local_permissions.initMasks(PERM_ALL, PERM_ALL, everyone_perm, group_perm, next_owner_perm); + if (mIsOverride) + { + // Shouldn't happen, but just in case it ever changes + U32 everyone_perm = LLFloaterPerms::getEveryonePerms("Materials"); + U32 group_perm = LLFloaterPerms::getGroupPerms("Materials"); + U32 next_owner_perm = LLFloaterPerms::getNextOwnerPerms("Materials"); + local_permissions.initMasks(PERM_ALL, PERM_ALL, everyone_perm, group_perm, next_owner_perm); + + } + else + { + // Uploads are supposed to use Upload permissions, not material permissions + U32 everyone_perm = LLFloaterPerms::getEveryonePerms("Uploads"); + U32 group_perm = LLFloaterPerms::getGroupPerms("Uploads"); + U32 next_owner_perm = LLFloaterPerms::getNextOwnerPerms("Uploads"); + local_permissions.initMasks(PERM_ALL, PERM_ALL, everyone_perm, group_perm, next_owner_perm); + } std::string res_desc = buildMaterialDescription(); createInventoryItem(buffer, mMaterialName, res_desc, local_permissions); diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 1b6f35202e..6494d445fe 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1430,7 +1430,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry) U8* buffer = new(std::nothrow) U8[size]; if (!buffer) { - LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for skin info, size: " << size << LL_ENDL; + LL_WARNS(LOG_MESH) << "Failed to allocate memory for skin info, size: " << size << LL_ENDL; return false; } LLMeshRepository::sCacheBytesRead += size; @@ -1550,7 +1550,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) U8* buffer = new(std::nothrow) U8[size]; if (!buffer) { - LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for mesh decomposition, size: " << size << LL_ENDL; + LL_WARNS(LOG_MESH) << "Failed to allocate memory for mesh decomposition, size: " << size << LL_ENDL; return false; } LLMeshRepository::sCacheBytesRead += size; @@ -1659,7 +1659,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) U8* buffer = new(std::nothrow) U8[size]; if (!buffer) { - LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for physics shape, size: " << size << LL_ENDL; + LL_WARNS(LOG_MESH) << "Failed to allocate memory for physics shape, size: " << size << LL_ENDL; return false; } file.read(buffer, size); @@ -1868,7 +1868,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U8* buffer = new(std::nothrow) U8[size]; if (!buffer) { - LL_WARNS_ONCE(LOG_MESH) << "Can't allocate memory for mesh " << mesh_id << " LOD " << lod << ", size: " << size << LL_ENDL; + LL_WARNS(LOG_MESH) << "Can't allocate memory for mesh " << mesh_id << " LOD " << lod << ", size: " << size << LL_ENDL; // todo: for now it will result in indefinite constant retries, should result in timeout // or in retry-count and disabling mesh. (but usually viewer is beyond saving at this point) return false; @@ -5754,7 +5754,7 @@ void on_new_single_inventory_upload_complete( } else { - LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, server_response["new_inventory_item"].asUUID(), TRUE, TAKE_FOCUS_NO, TRUE); + LLInventoryPanel::openInventoryPanelAndSetSelection(true, server_response["new_inventory_item"].asUUID(), true, false, true); } // restore keyboard focus diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index fde68b1db5..afa5fcda9d 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -311,7 +311,7 @@ void LLModelPreview::updateDimentionsAndOffsets() { accounted.insert(instance.mModel); - //update instance skin info for each lods pelvisZoffset + // update instance skin info for each lods pelvisZoffset for (int j = 0; jsecond.begin(); model_iter != iter->second.end();) - { //for each instance with said transform applied + { // for each instance with said transform applied LLModelInstance instance = *model_iter++; LLModel* base_model = instance.mModel; @@ -804,7 +805,7 @@ void LLModelPreview::rebuildUploadData() // || getLoadState() == LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION) { - // This is only valid for these two error types because they are + // This is only valid for these two error types because they are // only used inside rebuildUploadData() and updateStatusMessages() // updateStatusMessages() is called after rebuildUploadData() setLoadState(LLModelLoader::DONE); @@ -1049,7 +1050,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable // it tends to force the UI into strange checkbox options // which cannot be altered. - //only try to load from slm if viewer is configured to do so and this is the + //only try to load from slm if viewer is configured to do so and this is the //initial model load (not an LoD or physics shape) mModelLoader->mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mUploadData.empty(); } @@ -1168,12 +1169,13 @@ void LLModelPreview::clearIncompatible(S32 lod) // Check if already started bool subscribe_for_generation = mLodsQuery.empty(); - + // Remove previously scheduled work mLodsQuery.clear(); LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (!fmp) return; + if (!fmp) + return; // Schedule new work for (S32 i = LLModel::LOD_HIGH; i >= 0; --i) @@ -2536,7 +2538,7 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target ll_aligned_free_16(output_indices); ll_aligned_free_16(shadow_indices); - + if (size_new_indices < 3) { // At least one triangle is needed @@ -2745,7 +2747,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d { precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_UVS); } - + if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator)) { // Try sloppy variant if normal one failed to simplify model enough. diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index de988555c5..65ec38a41d 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -433,8 +433,7 @@ bool compareGalleryItem(LLOutfitGalleryItem* item1, LLOutfitGalleryItem* item2) } void LLOutfitGallery::reArrangeRows(S32 row_diff) -{ - +{ std::vector buf_items = mItems; for (std::vector::const_reverse_iterator it = buf_items.rbegin(); it != buf_items.rend(); ++it) { @@ -446,16 +445,24 @@ void LLOutfitGallery::reArrangeRows(S32 row_diff) } mHiddenItems.clear(); - mItemsInRow+= row_diff; + mItemsInRow += row_diff; updateGalleryWidth(); std::sort(buf_items.begin(), buf_items.end(), compareGalleryItem); - + + std::string cur_filter = getFilterSubString(); + LLStringUtil::toUpper(cur_filter); + for (std::vector::const_iterator it = buf_items.begin(); it != buf_items.end(); ++it) { - (*it)->setHidden(false); - applyFilter(*it,sFilterSubString); + std::string outfit_name = (*it)->getItemName(); + LLStringUtil::toUpper(outfit_name); + + bool hidden = (std::string::npos == outfit_name.find(cur_filter)); + (*it)->setHidden(hidden); + addToGallery(*it); } + updateMessageVisibility(); } @@ -725,9 +732,9 @@ LLOutfitGallery::~LLOutfitGallery() } } -void LLOutfitGallery::setFilterSubString(const std::string& string) +// virtual +void LLOutfitGallery::onFilterSubStringChanged(const std::string& new_string, const std::string& old_string) { - sFilterSubString = string; reArrangeRows(); } @@ -743,20 +750,6 @@ void LLOutfitGallery::onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id) } } -void LLOutfitGallery::applyFilter(LLOutfitGalleryItem* item, const std::string& filter_substring) -{ - if (!item) return; - - std::string outfit_name = item->getItemName(); - LLStringUtil::toUpper(outfit_name); - - std::string cur_filter = filter_substring; - LLStringUtil::toUpper(cur_filter); - - bool hidden = (std::string::npos == outfit_name.find(cur_filter)); - item->setHidden(hidden); -} - void LLOutfitGallery::onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid) { } @@ -904,11 +897,11 @@ bool LLOutfitGallery::hasDefaultImage(const LLUUID& outfit_cat_id) void LLOutfitGallery::updateMessageVisibility() { - if(mItems.empty()) + if (mItems.empty()) { mMessageTextBox->setVisible(TRUE); mScrollPanel->setVisible(FALSE); - std::string message = sFilterSubString.empty()? getString("no_outfits_msg") : getString("no_matched_outfits_msg"); + std::string message = getString(getFilterSubString().empty() ? "no_outfits_msg" : "no_matched_outfits_msg"); mMessageTextBox->setValue(message); } else @@ -1101,8 +1094,11 @@ bool LLOutfitGalleryItem::openOutfitsContent() { outfit_list->setSelectedOutfitByUUID(mUUID); LLAccordionCtrlTab* tab = accordion->getSelectedTab(); - tab->showAndFocusHeader(); - return true; + if (tab) + { + tab->showAndFocusHeader(); + return true; + } } } } diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h index 9915752962..f2366e6494 100644 --- a/indra/newview/lloutfitgallery.h +++ b/indra/newview/lloutfitgallery.h @@ -90,7 +90,7 @@ public: void wearSelectedOutfit(); - /*virtual*/ void setFilterSubString(const std::string& string); + /*virtual*/ void onFilterSubStringChanged(const std::string& new_string, const std::string& old_string); /*virtual*/ void getCurrentCategories(uuid_vec_t& vcur); /*virtual*/ void updateAddedCategory(LLUUID cat_id); @@ -117,8 +117,6 @@ protected: /*virtual*/ void onExpandAllFolders() {} /*virtual*/ LLOutfitListGearMenuBase* createGearMenu(); - void applyFilter(LLOutfitGalleryItem* item, const std::string& filter_substring); - private: LLUUID getPhotoAssetId(const LLUUID& outfit_id); LLUUID getDefaultPhoto(); diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 08ed61aab2..b88fa87de2 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -201,7 +201,7 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id) list->setCommitCallback(boost::bind(&LLOutfitsList::onListSelectionChange, this, _1)); // Setting list refresh callback to apply filter on list change. - list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1)); + list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onRefreshComplete, this, _1)); list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3)); @@ -212,19 +212,17 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id) // Further list updates will be triggered by the category observer. list->updateList(cat_id); - // If filter is currently applied we store the initial tab state and - // open it to show matched items if any. - if (!sFilterSubString.empty()) + // If filter is currently applied we store the initial tab state. + if (!getFilterSubString().empty()) { tab->notifyChildren(LLSD().with("action", "store_state")); - tab->setDisplayChildren(true); // Setting mForceRefresh flag will make the list refresh its contents // even if it is not currently visible. This is required to apply the // filter to the newly added list. list->setForceRefresh(true); - list->setFilterSubString(sFilterSubString); + list->setFilterSubString(getFilterSubString(), false); } } @@ -383,14 +381,6 @@ void LLOutfitsList::onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid) } } -// virtual -void LLOutfitsList::setFilterSubString(const std::string& string) -{ - applyFilter(string); - - sFilterSubString = string; -} - // virtual bool LLOutfitListBase::isActionEnabled(const LLSD& userdata) { @@ -564,9 +554,9 @@ void LLOutfitsList::restoreOutfitSelection(LLAccordionCtrlTab* tab, const LLUUID } } -void LLOutfitsList::onFilteredWearableItemsListRefresh(LLUICtrl* ctrl) +void LLOutfitsList::onRefreshComplete(LLUICtrl* ctrl) { - if (!ctrl || sFilterSubString.empty()) + if (!ctrl || getFilterSubString().empty()) return; for (outfits_map_t::iterator @@ -580,57 +570,50 @@ void LLOutfitsList::onFilteredWearableItemsListRefresh(LLUICtrl* ctrl) LLWearableItemsList* list = dynamic_cast(tab->getAccordionView()); if (list != ctrl) continue; - applyFilterToTab(iter->first, tab, sFilterSubString); + applyFilterToTab(iter->first, tab, getFilterSubString()); } } -void LLOutfitsList::applyFilter(const std::string& new_filter_substring) +// virtual +void LLOutfitsList::onFilterSubStringChanged(const std::string& new_string, const std::string& old_string) { - mAccordion->setFilterSubString(new_filter_substring); + mAccordion->setFilterSubString(new_string); - for (outfits_map_t::iterator - iter = mOutfitsMap.begin(), - iter_end = mOutfitsMap.end(); - iter != iter_end; ++iter) + outfits_map_t::iterator iter = mOutfitsMap.begin(), iter_end = mOutfitsMap.end(); + while (iter != iter_end) { - LLAccordionCtrlTab* tab = iter->second; + const LLUUID& category_id = iter->first; + LLAccordionCtrlTab* tab = iter++->second; if (!tab) continue; - bool more_restrictive = sFilterSubString.size() < new_filter_substring.size() && !new_filter_substring.substr(0, sFilterSubString.size()).compare(sFilterSubString); - - // Restore tab visibility in case of less restrictive filter - // to compare it with updated string if it was previously hidden. - if (!more_restrictive) - { - tab->setVisible(TRUE); - } - LLWearableItemsList* list = dynamic_cast(tab->getAccordionView()); if (list) { - list->setFilterSubString(new_filter_substring); + list->setFilterSubString(new_string, tab->getDisplayChildren()); } - if(sFilterSubString.empty() && !new_filter_substring.empty()) + if (old_string.empty()) { - //store accordion tab state when filter is not empty - tab->notifyChildren(LLSD().with("action","store_state")); + // Store accordion tab state when filter is not empty + tab->notifyChildren(LLSD().with("action", "store_state")); } - if (!new_filter_substring.empty()) + if (!new_string.empty()) { - applyFilterToTab(iter->first, tab, new_filter_substring); + applyFilterToTab(category_id, tab, new_string); } else { - // restore tab title when filter is empty + tab->setVisible(TRUE); + + // Restore tab title when filter is empty tab->setTitle(tab->getTitle()); - //restore accordion state after all those accodrion tab manipulations - tab->notifyChildren(LLSD().with("action","restore_state")); + // Restore accordion state after all those accodrion tab manipulations + tab->notifyChildren(LLSD().with("action", "restore_state")); // Try restoring the tab selection. - restoreOutfitSelection(tab, iter->first); + restoreOutfitSelection(tab, category_id); } } @@ -656,11 +639,11 @@ void LLOutfitsList::applyFilterToTab( if (std::string::npos == title.find(cur_filter)) { - // hide tab if its title doesn't pass filter - // and it has no visible items + // Hide tab if its title doesn't pass filter + // and it has no matched items tab->setVisible(list->hasMatchedItems()); - // remove title highlighting because it might + // Remove title highlighting because it might // have been previously highlighted by less restrictive filter tab->setTitle(tab->getTitle()); @@ -672,18 +655,6 @@ void LLOutfitsList::applyFilterToTab( // Try restoring the tab selection. restoreOutfitSelection(tab, category_id); } - - if (tab->getVisible()) - { - // Open tab if it has passed the filter. - tab->setDisplayChildren(true); - } - else - { - // Set force refresh flag to refresh not visible list - // when some changes occur in it. - list->setForceRefresh(true); - } } bool LLOutfitsList::canWearSelected() @@ -768,11 +739,10 @@ void LLOutfitsList::onCOFChanged() // These links UUIDs are not the same UUIDs that we have in each wearable items list. // So we collect base items' UUIDs to find them or links that point to them in wearable // items lists and update their worn state there. - for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); - iter != item_array.end(); - ++iter) + LLInventoryModel::item_array_t::const_iterator array_iter = item_array.begin(), array_end = item_array.end(); + while (array_iter < array_end) { - vnew.push_back((*iter)->getLinkedUUID()); + vnew.push_back((*(array_iter++))->getLinkedUUID()); } // We need to update only items that were added or removed from COF. @@ -781,20 +751,20 @@ void LLOutfitsList::onCOFChanged() // Store the ids of items currently linked from COF. mCOFLinkedItems = vnew; - for (outfits_map_t::iterator iter = mOutfitsMap.begin(); - iter != mOutfitsMap.end(); - ++iter) + // Append removed ids to added ids because we should update all of them. + vadded.reserve(vadded.size() + vremoved.size()); + vadded.insert(vadded.end(), vremoved.begin(), vremoved.end()); + vremoved.clear(); + + outfits_map_t::iterator map_iter = mOutfitsMap.begin(), map_end = mOutfitsMap.end(); + while (map_iter != map_end) { - LLAccordionCtrlTab* tab = iter->second; + LLAccordionCtrlTab* tab = (map_iter++)->second; if (!tab) continue; LLWearableItemsList* list = dynamic_cast(tab->getAccordionView()); if (!list) continue; - // Append removed ids to added ids because we should update all of them. - vadded.reserve(vadded.size() + vremoved.size()); - vadded.insert(vadded.end(), vremoved.begin(), vremoved.end()); - // Every list updates the labels of changed items or // the links that point to these items. list->updateChangedItems(vadded); @@ -906,7 +876,6 @@ void LLOutfitListBase::onOpen(const LLSD& info) // arrive. category->fetch(); refreshList(outfits); - highlightBaseOutfit(); mIsInitialized = true; } @@ -914,12 +883,14 @@ void LLOutfitListBase::onOpen(const LLSD& info) void LLOutfitListBase::refreshList(const LLUUID& category_id) { + bool wasNull = mRefreshListState.CategoryUUID.isNull(); + mRefreshListState.CategoryUUID.setNull(); + LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; // Collect all sub-categories of a given category. // FIRE-6958/VWR-2862; Make sure to only collect folders of type FT_OUTFIT - class ndOutfitsCollector: public LLIsType { public: @@ -941,8 +912,8 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) // LLIsType is_category(LLAssetType::AT_CATEGORY); ndOutfitsCollector is_category; - // + gInventory.collectDescendentsIf( category_id, cat_array, @@ -950,22 +921,41 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) LLInventoryModel::EXCLUDE_TRASH, is_category); - uuid_vec_t vadded; - uuid_vec_t vremoved; + // Memorize item names for each UUID + std::map names; + for (const LLPointer& cat : cat_array) + { + names.emplace(std::make_pair(cat->getUUID(), cat->getName())); + } + + // Fill added and removed items vectors. + mRefreshListState.Added.clear(); + mRefreshListState.Removed.clear(); + computeDifference(cat_array, mRefreshListState.Added, mRefreshListState.Removed); + // Sort added items vector by item name. + std::sort(mRefreshListState.Added.begin(), mRefreshListState.Added.end(), + [names](const LLUUID& a, const LLUUID& b) + { + return LLStringUtil::compareDict(names.at(a), names.at(b)) < 0; + }); + // Initialize iterators for added and removed items vectors. + mRefreshListState.AddedIterator = mRefreshListState.Added.begin(); + mRefreshListState.RemovedIterator = mRefreshListState.Removed.begin(); + + LL_INFOS() << "added: " << mRefreshListState.Added.size() << + ", removed: " << mRefreshListState.Removed.size() << + ", changed: " << gInventory.getChangedIDs().size() << + LL_ENDL; + + mRefreshListState.CategoryUUID = category_id; + if (wasNull) + { + gIdleCallbacks.addFunction(onIdle, this); + } - // Create added and removed items vectors. - computeDifference(cat_array, vadded, vremoved); - // FIRE-6958/VWR-2862; Handle large amounts of outfits, write a least a warning into the logs. - if( vadded.size() > 128 ) - LL_WARNS() << "Large amount of outfits found: " << vadded.size() << " this may cause hangs and disconnects" << LL_ENDL; - - U32 nCap = gSavedSettings.getU32( "FSDisplaySavedOutfitsCap" ); - if( nCap && nCap < vadded.size() ) - { - vadded.resize( nCap ); - LL_WARNS() << "Capped outfits to " << nCap << " due to debug setting FSDisplaySavedOutfitsCap" << LL_ENDL; - } + if (mRefreshListState.Added.size() > 128) + LL_WARNS() << "Large amount of outfits found: " << mRefreshListState.Added.size() << " this may cause hangs and disconnects" << LL_ENDL; // // FIRE-12939: Add outfit count to outfits list @@ -976,25 +966,53 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) getChild("OutfitcountText")->setTextArg("COUNT", count_string); } // +} + +// static +void LLOutfitListBase::onIdle(void* userdata) +{ + LLOutfitListBase* self = (LLOutfitListBase*)userdata; + + self->onIdleRefreshList(); +} + +void LLOutfitListBase::onIdleRefreshList() +{ + if (mRefreshListState.CategoryUUID.isNull()) + return; + + const F64 MAX_TIME = 0.05f; + F64 curent_time = LLTimer::getTotalSeconds(); + const F64 end_time = curent_time + MAX_TIME; // Handle added tabs. - for (uuid_vec_t::const_iterator iter = vadded.begin(); - iter != vadded.end(); - ++iter) + while (mRefreshListState.AddedIterator < mRefreshListState.Added.end()) { - const LLUUID cat_id = (*iter); + const LLUUID cat_id = (*mRefreshListState.AddedIterator++); updateAddedCategory(cat_id); + + curent_time = LLTimer::getTotalSeconds(); + if (curent_time >= end_time) + return; } + mRefreshListState.Added.clear(); + mRefreshListState.AddedIterator = mRefreshListState.Added.end(); // We called mAccordion->addCollapsibleCtrl with false as second paramter and did not let it arrange itself each time. Do this here after all is said and done. arrange(); // Handle removed tabs. - for (uuid_vec_t::const_iterator iter = vremoved.begin(); iter != vremoved.end(); ++iter) + while (mRefreshListState.RemovedIterator < mRefreshListState.Removed.end()) { - const LLUUID cat_id = (*iter); + const LLUUID cat_id = (*mRefreshListState.RemovedIterator++); updateRemovedCategory(cat_id); + + curent_time = LLTimer::getTotalSeconds(); + if (curent_time >= end_time) + return; } + mRefreshListState.Removed.clear(); + mRefreshListState.RemovedIterator = mRefreshListState.Removed.end(); // Get changed items from inventory model and update outfit tabs // which might have been renamed. @@ -1007,9 +1025,9 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) if (!cat) { LLInventoryObject* obj = gInventory.getObject(*items_iter); - if(!obj || (obj->getType() != LLAssetType::AT_CATEGORY)) + if (!obj || (obj->getType() != LLAssetType::AT_CATEGORY)) { - return; + break; } cat = (LLViewerInventoryCategory*)obj; } @@ -1019,6 +1037,12 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) } sortOutfits(); + highlightBaseOutfit(); + + gIdleCallbacks.deleteFunction(onIdle, this); + mRefreshListState.CategoryUUID.setNull(); + + LL_INFOS() << "done" << LL_ENDL; } void LLOutfitListBase::computeDifference( @@ -1055,7 +1079,6 @@ void LLOutfitListBase::highlightBaseOutfit() mHighlightedOutfitUUID = base_id; onHighlightBaseOutfit(base_id, prev_id); } - } void LLOutfitListBase::removeSelected() diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index b85ee81c78..53bbfddef7 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -121,8 +121,20 @@ protected: void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response); virtual void onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id) = 0; + static void onIdle(void* userdata); + void onIdleRefreshList(); + + struct + { + LLUUID CategoryUUID; + uuid_vec_t Added; + uuid_vec_t Removed; + uuid_vec_t::const_iterator AddedIterator; + uuid_vec_t::const_iterator RemovedIterator; + } mRefreshListState; + bool mIsInitialized; - LLInventoryCategoriesObserver* mCategoriesObserver; + LLInventoryCategoriesObserver* mCategoriesObserver; LLUUID mSelectedOutfitUUID; // id of currently highlited outfit LLUUID mHighlightedOutfitUUID; @@ -232,7 +244,7 @@ public: //void performAction(std::string action); - /*virtual*/ void setFilterSubString(const std::string& string); + /*virtual*/ void onFilterSubStringChanged(const std::string& new_string, const std::string& old_string); /*virtual*/ void getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const; @@ -303,12 +315,7 @@ private: * Called upon list refresh event to update tab visibility depending on * the results of applying filter to the title and list items of the tab. */ - void onFilteredWearableItemsListRefresh(LLUICtrl* ctrl); - - /** - * Highlights filtered items and hides tabs which haven't passed filter. - */ - void applyFilter(const std::string& new_filter_substring); + void onRefreshComplete(LLUICtrl* ctrl); /** * Applies filter to the given tab diff --git a/indra/newview/llpanelappearancetab.cpp b/indra/newview/llpanelappearancetab.cpp index fdb331163b..81a6cf082a 100644 --- a/indra/newview/llpanelappearancetab.cpp +++ b/indra/newview/llpanelappearancetab.cpp @@ -28,7 +28,6 @@ #include "llpanelappearancetab.h" - #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llviewerinventory.h" @@ -37,7 +36,31 @@ #include "rlvhandler.h" // [/RLVa:KB] -//virtual +std::string LLPanelAppearanceTab::sRecentFilterSubString; + +void LLPanelAppearanceTab::setFilterSubString(const std::string& new_string) +{ + if (new_string != mFilterSubString) + { + std::string old_string = mFilterSubString; + mFilterSubString = new_string; + onFilterSubStringChanged(mFilterSubString, old_string); + } + + sRecentFilterSubString = new_string; +} + +void LLPanelAppearanceTab::checkFilterSubString() +{ + if (sRecentFilterSubString != mFilterSubString) + { + std::string old_string = mFilterSubString; + mFilterSubString = sRecentFilterSubString; + onFilterSubStringChanged(mFilterSubString, old_string); + } +} + +// virtual bool LLPanelAppearanceTab::canTakeOffSelected() { uuid_vec_t selected_uuids; diff --git a/indra/newview/llpanelappearancetab.h b/indra/newview/llpanelappearancetab.h index 2ed6b00497..e81394dd3c 100644 --- a/indra/newview/llpanelappearancetab.h +++ b/indra/newview/llpanelappearancetab.h @@ -35,13 +35,17 @@ public: LLPanelAppearanceTab() : LLPanel() {} virtual ~LLPanelAppearanceTab() {} - virtual void setFilterSubString(const std::string& string) = 0; + void setFilterSubString(const std::string& new_string); + + void checkFilterSubString(); + + virtual void onFilterSubStringChanged(const std::string& new_string, const std::string& old_string) = 0; virtual bool isActionEnabled(const LLSD& userdata) = 0; virtual void getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const {} - static const std::string& getFilterSubString() { return sFilterSubString; } + const std::string& getFilterSubString() { return mFilterSubString; } protected: @@ -50,7 +54,10 @@ protected: */ bool canTakeOffSelected(); - static std::string sFilterSubString; +private: + std::string mFilterSubString; + + static std::string sRecentFilterSubString; }; #endif //LL_LLPANELAPPEARANCETAB_H diff --git a/indra/newview/llpaneleditwater.cpp b/indra/newview/llpaneleditwater.cpp index a09964e17d..cf536dd87e 100644 --- a/indra/newview/llpaneleditwater.cpp +++ b/indra/newview/llpaneleditwater.cpp @@ -89,7 +89,7 @@ BOOL LLPanelSettingsWaterMainTab::postBuild() getChild(FIELD_WATER_UNDERWATER_MOD)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onFogUnderWaterChanged(); }); mTxtNormalMap->setDefaultImageAssetID(LLSettingsWater::GetDefaultWaterNormalAssetId()); - mTxtNormalMap->setBlankImageAssetID(LLUUID( gSavedSettings.getString( "DefaultBlankNormalTexture" ))); + mTxtNormalMap->setBlankImageAssetID(BLANK_OBJECT_NORMAL); mTxtNormalMap->setCommitCallback([this](LLUICtrl *, const LLSD &) { onNormalMapChanged(); }); getChild(FIELD_WATER_WAVE2_XY)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onSmallWaveChanged(); }); diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 05838e8af3..739719a73c 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -102,7 +102,7 @@ enum ESubpart { SUBPART_SKIRT, SUBPART_ALPHA, SUBPART_TATTOO, - SUBPART_UNIVERSAL, + SUBPART_UNIVERSAL, SUBPART_PHYSICS_BREASTS_UPDOWN, SUBPART_PHYSICS_BREASTS_INOUT, SUBPART_PHYSICS_BREASTS_LEFTRIGHT, @@ -125,7 +125,7 @@ class LLEditWearableDictionary : public LLSingleton //-------------------------------------------------------------------- LLSINGLETON(LLEditWearableDictionary); virtual ~LLEditWearableDictionary(); - + //-------------------------------------------------------------------- // Wearable Types //-------------------------------------------------------------------- @@ -219,7 +219,6 @@ public: LLEditWearableDictionary::LLEditWearableDictionary() { - } //virtual @@ -232,23 +231,23 @@ LLEditWearableDictionary::Wearables::Wearables() // note the subpart that is listed first is treated as "default", regardless of what order is in enum. // Please match the order presented in XUI. -Nyx // this will affect what camera angle is shown when first editing a wearable - addEntry(LLWearableType::WT_SHAPE, new WearableEntry(LLWearableType::WT_SHAPE,"edit_shape_title","shape_desc_text", texture_vec_t(), texture_vec_t(), subpart_vec_t{SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS})); - addEntry(LLWearableType::WT_SKIN, new WearableEntry(LLWearableType::WT_SKIN,"edit_skin_title","skin_desc_text", texture_vec_t(), texture_vec_t{TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT}, subpart_vec_t{SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL})); - addEntry(LLWearableType::WT_HAIR, new WearableEntry(LLWearableType::WT_HAIR,"edit_hair_title","hair_desc_text", texture_vec_t(), texture_vec_t{TEX_HAIR}, subpart_vec_t{SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL})); - addEntry(LLWearableType::WT_EYES, new WearableEntry(LLWearableType::WT_EYES,"edit_eyes_title","eyes_desc_text", texture_vec_t(), texture_vec_t{TEX_EYES_IRIS}, subpart_vec_t{SUBPART_EYES})); - addEntry(LLWearableType::WT_SHIRT, new WearableEntry(LLWearableType::WT_SHIRT,"edit_shirt_title","shirt_desc_text", texture_vec_t{TEX_UPPER_SHIRT}, texture_vec_t{TEX_UPPER_SHIRT}, subpart_vec_t{SUBPART_SHIRT})); - addEntry(LLWearableType::WT_PANTS, new WearableEntry(LLWearableType::WT_PANTS,"edit_pants_title","pants_desc_text", texture_vec_t{TEX_LOWER_PANTS}, texture_vec_t{TEX_LOWER_PANTS}, subpart_vec_t{SUBPART_PANTS})); - addEntry(LLWearableType::WT_SHOES, new WearableEntry(LLWearableType::WT_SHOES,"edit_shoes_title","shoes_desc_text", texture_vec_t{TEX_LOWER_SHOES}, texture_vec_t{TEX_LOWER_SHOES}, subpart_vec_t{SUBPART_SHOES})); - addEntry(LLWearableType::WT_SOCKS, new WearableEntry(LLWearableType::WT_SOCKS,"edit_socks_title","socks_desc_text", texture_vec_t{TEX_LOWER_SOCKS}, texture_vec_t{TEX_LOWER_SOCKS}, subpart_vec_t{SUBPART_SOCKS})); + addEntry(LLWearableType::WT_SHAPE, new WearableEntry(LLWearableType::WT_SHAPE,"edit_shape_title","shape_desc_text", texture_vec_t(), texture_vec_t(), subpart_vec_t{SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS})); + addEntry(LLWearableType::WT_SKIN, new WearableEntry(LLWearableType::WT_SKIN,"edit_skin_title","skin_desc_text", texture_vec_t(), texture_vec_t{TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT}, subpart_vec_t{SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL})); + addEntry(LLWearableType::WT_HAIR, new WearableEntry(LLWearableType::WT_HAIR,"edit_hair_title","hair_desc_text", texture_vec_t(), texture_vec_t{TEX_HAIR}, subpart_vec_t{SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL})); + addEntry(LLWearableType::WT_EYES, new WearableEntry(LLWearableType::WT_EYES,"edit_eyes_title","eyes_desc_text", texture_vec_t(), texture_vec_t{TEX_EYES_IRIS}, subpart_vec_t{SUBPART_EYES})); + addEntry(LLWearableType::WT_SHIRT, new WearableEntry(LLWearableType::WT_SHIRT,"edit_shirt_title","shirt_desc_text", texture_vec_t{TEX_UPPER_SHIRT}, texture_vec_t{TEX_UPPER_SHIRT}, subpart_vec_t{SUBPART_SHIRT})); + addEntry(LLWearableType::WT_PANTS, new WearableEntry(LLWearableType::WT_PANTS,"edit_pants_title","pants_desc_text", texture_vec_t{TEX_LOWER_PANTS}, texture_vec_t{TEX_LOWER_PANTS}, subpart_vec_t{SUBPART_PANTS})); + addEntry(LLWearableType::WT_SHOES, new WearableEntry(LLWearableType::WT_SHOES,"edit_shoes_title","shoes_desc_text", texture_vec_t{TEX_LOWER_SHOES}, texture_vec_t{TEX_LOWER_SHOES}, subpart_vec_t{SUBPART_SHOES})); + addEntry(LLWearableType::WT_SOCKS, new WearableEntry(LLWearableType::WT_SOCKS,"edit_socks_title","socks_desc_text", texture_vec_t{TEX_LOWER_SOCKS}, texture_vec_t{TEX_LOWER_SOCKS}, subpart_vec_t{SUBPART_SOCKS})); addEntry(LLWearableType::WT_JACKET, new WearableEntry(LLWearableType::WT_JACKET,"edit_jacket_title","jacket_desc_text", texture_vec_t{TEX_UPPER_JACKET}, texture_vec_t{TEX_UPPER_JACKET, TEX_LOWER_JACKET}, subpart_vec_t{SUBPART_JACKET})); addEntry(LLWearableType::WT_GLOVES, new WearableEntry(LLWearableType::WT_GLOVES,"edit_gloves_title","gloves_desc_text", texture_vec_t{TEX_UPPER_GLOVES}, texture_vec_t{TEX_UPPER_GLOVES}, subpart_vec_t{SUBPART_GLOVES})); addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(LLWearableType::WT_UNDERSHIRT,"edit_undershirt_title","undershirt_desc_text", texture_vec_t{TEX_UPPER_UNDERSHIRT}, texture_vec_t{TEX_UPPER_UNDERSHIRT}, subpart_vec_t{SUBPART_UNDERSHIRT})); addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(LLWearableType::WT_UNDERPANTS,"edit_underpants_title","underpants_desc_text", texture_vec_t{TEX_LOWER_UNDERPANTS}, texture_vec_t{TEX_LOWER_UNDERPANTS}, subpart_vec_t{SUBPART_UNDERPANTS})); - addEntry(LLWearableType::WT_SKIRT, new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title","skirt_desc_text", texture_vec_t{TEX_SKIRT}, texture_vec_t{TEX_SKIRT}, subpart_vec_t{SUBPART_SKIRT})); - addEntry(LLWearableType::WT_ALPHA, new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title","alpha_desc_text", texture_vec_t(), texture_vec_t{TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA}, subpart_vec_t{SUBPART_ALPHA})); + addEntry(LLWearableType::WT_SKIRT, new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title","skirt_desc_text", texture_vec_t{TEX_SKIRT}, texture_vec_t{TEX_SKIRT}, subpart_vec_t{SUBPART_SKIRT})); + addEntry(LLWearableType::WT_ALPHA, new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title","alpha_desc_text", texture_vec_t(), texture_vec_t{TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA}, subpart_vec_t{SUBPART_ALPHA})); addEntry(LLWearableType::WT_TATTOO, new WearableEntry(LLWearableType::WT_TATTOO,"edit_tattoo_title","tattoo_desc_text", texture_vec_t{TEX_HEAD_TATTOO}, texture_vec_t{TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO}, subpart_vec_t{SUBPART_TATTOO})); - addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(LLWearableType::WT_UNIVERSAL, "edit_universal_title", "universal_desc_text", texture_vec_t{ TEX_HEAD_UNIVERSAL_TATTOO }, texture_vec_t{ TEX_HEAD_UNIVERSAL_TATTOO, TEX_UPPER_UNIVERSAL_TATTOO, TEX_LOWER_UNIVERSAL_TATTOO, TEX_SKIRT_TATTOO, TEX_HAIR_TATTOO, TEX_EYES_TATTOO, TEX_LEFT_ARM_TATTOO, TEX_LEFT_LEG_TATTOO, TEX_AUX1_TATTOO, TEX_AUX2_TATTOO, TEX_AUX3_TATTOO }, subpart_vec_t{ SUBPART_UNIVERSAL })); - addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(LLWearableType::WT_PHYSICS,"edit_physics_title","physics_desc_text", texture_vec_t(), texture_vec_t(), subpart_vec_t{SUBPART_PHYSICS_BREASTS_UPDOWN, SUBPART_PHYSICS_BREASTS_INOUT, SUBPART_PHYSICS_BREASTS_LEFTRIGHT, SUBPART_PHYSICS_BELLY_UPDOWN, SUBPART_PHYSICS_BUTT_UPDOWN, SUBPART_PHYSICS_BUTT_LEFTRIGHT, SUBPART_PHYSICS_ADVANCED})); + addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(LLWearableType::WT_UNIVERSAL, "edit_universal_title", "universal_desc_text", texture_vec_t{ TEX_HEAD_UNIVERSAL_TATTOO }, texture_vec_t{ TEX_HEAD_UNIVERSAL_TATTOO, TEX_UPPER_UNIVERSAL_TATTOO, TEX_LOWER_UNIVERSAL_TATTOO, TEX_SKIRT_TATTOO, TEX_HAIR_TATTOO, TEX_EYES_TATTOO, TEX_LEFT_ARM_TATTOO, TEX_LEFT_LEG_TATTOO, TEX_AUX1_TATTOO, TEX_AUX2_TATTOO, TEX_AUX3_TATTOO }, subpart_vec_t{ SUBPART_UNIVERSAL })); + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(LLWearableType::WT_PHYSICS, "edit_physics_title", "physics_desc_text", texture_vec_t(), texture_vec_t(), subpart_vec_t{ SUBPART_PHYSICS_BREASTS_UPDOWN, SUBPART_PHYSICS_BREASTS_INOUT, SUBPART_PHYSICS_BREASTS_LEFTRIGHT, SUBPART_PHYSICS_BELLY_UPDOWN, SUBPART_PHYSICS_BUTT_UPDOWN, SUBPART_PHYSICS_BUTT_LEFTRIGHT, SUBPART_PHYSICS_ADVANCED })); } LLEditWearableDictionary::WearableEntry::WearableEntry(LLWearableType::EType type, @@ -264,60 +263,68 @@ LLEditWearableDictionary::WearableEntry::WearableEntry(LLWearableType::EType typ mSubparts(subparts), mColorSwatchCtrls(color_swatches), mTextureCtrls(texture_pickers) -{} +{ +} LLEditWearableDictionary::Subparts::Subparts() { - addEntry(SUBPART_SHAPE_WHOLE, new SubpartEntry(SUBPART_SHAPE_WHOLE, "mPelvis", "shape_body","shape_body_param_list", "shape_body_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); - addEntry(SUBPART_SHAPE_HEAD, new SubpartEntry(SUBPART_SHAPE_HEAD, "mHead", "shape_head", "shape_head_param_list", "shape_head_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); - addEntry(SUBPART_SHAPE_EYES, new SubpartEntry(SUBPART_SHAPE_EYES, "mHead", "shape_eyes", "shape_eyes_param_list", "shape_eyes_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); - addEntry(SUBPART_SHAPE_EARS, new SubpartEntry(SUBPART_SHAPE_EARS, "mHead", "shape_ears", "shape_ears_param_list", "shape_ears_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); - addEntry(SUBPART_SHAPE_NOSE, new SubpartEntry(SUBPART_SHAPE_NOSE, "mHead", "shape_nose", "shape_nose_param_list", "shape_nose_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); - addEntry(SUBPART_SHAPE_MOUTH, new SubpartEntry(SUBPART_SHAPE_MOUTH, "mHead", "shape_mouth", "shape_mouth_param_list", "shape_mouth_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); - addEntry(SUBPART_SHAPE_CHIN, new SubpartEntry(SUBPART_SHAPE_CHIN, "mHead", "shape_chin", "shape_chin_param_list", "shape_chin_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); - addEntry(SUBPART_SHAPE_TORSO, new SubpartEntry(SUBPART_SHAPE_TORSO, "mTorso", "shape_torso", "shape_torso_param_list", "shape_torso_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH)); - addEntry(SUBPART_SHAPE_LEGS, new SubpartEntry(SUBPART_SHAPE_LEGS, "mPelvis", "shape_legs", "shape_legs_param_list", "shape_legs_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); + // WT_SHAPE + addEntry(SUBPART_SHAPE_WHOLE, new SubpartEntry(SUBPART_SHAPE_WHOLE, "mPelvis", "shape_body","shape_body_param_list", "shape_body_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + addEntry(SUBPART_SHAPE_HEAD, new SubpartEntry(SUBPART_SHAPE_HEAD, "mHead", "shape_head", "shape_head_param_list", "shape_head_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); + addEntry(SUBPART_SHAPE_EYES, new SubpartEntry(SUBPART_SHAPE_EYES, "mHead", "shape_eyes", "shape_eyes_param_list", "shape_eyes_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); + addEntry(SUBPART_SHAPE_EARS, new SubpartEntry(SUBPART_SHAPE_EARS, "mHead", "shape_ears", "shape_ears_param_list", "shape_ears_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); + addEntry(SUBPART_SHAPE_NOSE, new SubpartEntry(SUBPART_SHAPE_NOSE, "mHead", "shape_nose", "shape_nose_param_list", "shape_nose_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); + addEntry(SUBPART_SHAPE_MOUTH, new SubpartEntry(SUBPART_SHAPE_MOUTH, "mHead", "shape_mouth", "shape_mouth_param_list", "shape_mouth_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); + addEntry(SUBPART_SHAPE_CHIN, new SubpartEntry(SUBPART_SHAPE_CHIN, "mHead", "shape_chin", "shape_chin_param_list", "shape_chin_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); + addEntry(SUBPART_SHAPE_TORSO, new SubpartEntry(SUBPART_SHAPE_TORSO, "mTorso", "shape_torso", "shape_torso_param_list", "shape_torso_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH)); + addEntry(SUBPART_SHAPE_LEGS, new SubpartEntry(SUBPART_SHAPE_LEGS, "mPelvis", "shape_legs", "shape_legs_param_list", "shape_legs_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); - addEntry(SUBPART_SKIN_COLOR, new SubpartEntry(SUBPART_SKIN_COLOR, "mHead", "skin_color", "skin_color_param_list", "skin_color_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); + // WT_SKIN + addEntry(SUBPART_SKIN_COLOR, new SubpartEntry(SUBPART_SKIN_COLOR, "mHead", "skin_color", "skin_color_param_list", "skin_color_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); addEntry(SUBPART_SKIN_FACEDETAIL, new SubpartEntry(SUBPART_SKIN_FACEDETAIL, "mHead", "skin_facedetail", "skin_face_param_list", "skin_face_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); - addEntry(SUBPART_SKIN_MAKEUP, new SubpartEntry(SUBPART_SKIN_MAKEUP, "mHead", "skin_makeup", "skin_makeup_param_list", "skin_makeup_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); + addEntry(SUBPART_SKIN_MAKEUP, new SubpartEntry(SUBPART_SKIN_MAKEUP, "mHead", "skin_makeup", "skin_makeup_param_list", "skin_makeup_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); addEntry(SUBPART_SKIN_BODYDETAIL, new SubpartEntry(SUBPART_SKIN_BODYDETAIL, "mPelvis", "skin_bodydetail", "skin_body_param_list", "skin_body_tab", LLVector3d(0.f, 0.f, -0.2f), LLVector3d(-2.5f, 0.5f, 0.5f),SEX_BOTH)); - addEntry(SUBPART_HAIR_COLOR, new SubpartEntry(SUBPART_HAIR_COLOR, "mHead", "hair_color", "hair_color_param_list", "hair_color_tab", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH)); - addEntry(SUBPART_HAIR_STYLE, new SubpartEntry(SUBPART_HAIR_STYLE, "mHead", "hair_style", "hair_style_param_list", "hair_style_tab", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH)); - addEntry(SUBPART_HAIR_EYEBROWS, new SubpartEntry(SUBPART_HAIR_EYEBROWS, "mHead", "hair_eyebrows", "hair_eyebrows_param_list", "hair_eyebrows_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); - addEntry(SUBPART_HAIR_FACIAL, new SubpartEntry(SUBPART_HAIR_FACIAL, "mHead", "hair_facial", "hair_facial_param_list", "hair_facial_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_MALE)); + // WT_HAIR + addEntry(SUBPART_HAIR_COLOR, new SubpartEntry(SUBPART_HAIR_COLOR, "mHead", "hair_color", "hair_color_param_list", "hair_color_tab", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH)); + addEntry(SUBPART_HAIR_STYLE, new SubpartEntry(SUBPART_HAIR_STYLE, "mHead", "hair_style", "hair_style_param_list", "hair_style_tab", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f), SEX_BOTH)); + addEntry(SUBPART_HAIR_EYEBROWS, new SubpartEntry(SUBPART_HAIR_EYEBROWS, "mHead", "hair_eyebrows", "hair_eyebrows_param_list", "hair_eyebrows_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); + addEntry(SUBPART_HAIR_FACIAL, new SubpartEntry(SUBPART_HAIR_FACIAL, "mHead", "hair_facial", "hair_facial_param_list", "hair_facial_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_MALE)); - addEntry(SUBPART_EYES, new SubpartEntry(SUBPART_EYES, "mHead", "eyes", "eyes_main_param_list", "eyes_main_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); + // WT_EYES + addEntry(SUBPART_EYES, new SubpartEntry(SUBPART_EYES, "mHead", "eyes", "eyes_main_param_list", "eyes_main_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH)); - addEntry(SUBPART_SHIRT, new SubpartEntry(SUBPART_SHIRT, "mTorso", "shirt", "shirt_main_param_list", "shirt_main_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH)); - addEntry(SUBPART_PANTS, new SubpartEntry(SUBPART_PANTS, "mPelvis", "pants", "pants_main_param_list", "pants_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); - addEntry(SUBPART_SHOES, new SubpartEntry(SUBPART_SHOES, "mPelvis", "shoes", "shoes_main_param_list", "shoes_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); - addEntry(SUBPART_SOCKS, new SubpartEntry(SUBPART_SOCKS, "mPelvis", "socks", "socks_main_param_list", "socks_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); - addEntry(SUBPART_JACKET, new SubpartEntry(SUBPART_JACKET, "mTorso", "jacket", "jacket_main_param_list", "jacket_main_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(-2.f, 0.1f, 0.3f),SEX_BOTH)); - addEntry(SUBPART_SKIRT, new SubpartEntry(SUBPART_SKIRT, "mPelvis", "skirt", "skirt_main_param_list", "skirt_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); - addEntry(SUBPART_GLOVES, new SubpartEntry(SUBPART_GLOVES, "mTorso", "gloves", "gloves_main_param_list", "gloves_main_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(-1.f, 0.15f, 0.f),SEX_BOTH)); - addEntry(SUBPART_UNDERSHIRT, new SubpartEntry(SUBPART_UNDERSHIRT, "mTorso", "undershirt", "undershirt_main_param_list", "undershirt_main_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH)); - addEntry(SUBPART_UNDERPANTS, new SubpartEntry(SUBPART_UNDERPANTS, "mPelvis", "underpants", "underpants_main_param_list", "underpants_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); + // WT_SHIRT, WT_PANTS, WT_SHOES, WT_SOCKS, WT_JACKET, WT_GLOVES, WT_UNDERSHIRT, WT_UNDERPANTS, WT_SKIRT, WT_ALPHA, WT_TATTOO, WT_UNIVERSAL + addEntry(SUBPART_SHIRT, new SubpartEntry(SUBPART_SHIRT, "mTorso", "shirt", "shirt_main_param_list", "shirt_main_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH)); + addEntry(SUBPART_PANTS, new SubpartEntry(SUBPART_PANTS, "mPelvis", "pants", "pants_main_param_list", "pants_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); + addEntry(SUBPART_SHOES, new SubpartEntry(SUBPART_SHOES, "mPelvis", "shoes", "shoes_main_param_list", "shoes_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); + addEntry(SUBPART_SOCKS, new SubpartEntry(SUBPART_SOCKS, "mPelvis", "socks", "socks_main_param_list", "socks_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); + addEntry(SUBPART_JACKET, new SubpartEntry(SUBPART_JACKET, "mTorso", "jacket", "jacket_main_param_list", "jacket_main_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(-2.f, 0.1f, 0.3f),SEX_BOTH)); + addEntry(SUBPART_GLOVES, new SubpartEntry(SUBPART_GLOVES, "mTorso", "gloves", "gloves_main_param_list", "gloves_main_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(-1.f, 0.15f, 0.f),SEX_BOTH)); + addEntry(SUBPART_UNDERSHIRT, new SubpartEntry(SUBPART_UNDERSHIRT, "mTorso", "undershirt", "undershirt_main_param_list", "undershirt_main_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH)); + addEntry(SUBPART_UNDERPANTS, new SubpartEntry(SUBPART_UNDERPANTS, "mPelvis", "underpants", "underpants_main_param_list", "underpants_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); + addEntry(SUBPART_SKIRT, new SubpartEntry(SUBPART_SKIRT, "mPelvis", "skirt", "skirt_main_param_list", "skirt_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); // Alpha, tattoo and universal don't adhere to the usual panel layout and don't have a param list and main tab - //addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha", "alpha_main_param_list", "alpha_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); - //addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", "tattoo_main_param_list", "tattoo_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); - //addEntry(SUBPART_UNIVERSAL, new SubpartEntry(SUBPART_UNIVERSAL, "mPelvis", "universal", "universal_main_param_list", "universal_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f), SEX_BOTH)); - addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha", "", "", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); - addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", "", "", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); - addEntry(SUBPART_UNIVERSAL, new SubpartEntry(SUBPART_UNIVERSAL, "mPelvis", "universal", "", "", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f), SEX_BOTH)); + //addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha", "alpha_main_param_list", "alpha_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + //addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", "tattoo_main_param_list", "tattoo_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + //addEntry(SUBPART_UNIVERSAL, new SubpartEntry(SUBPART_UNIVERSAL, "mPelvis", "universal", "universal_main_param_list", "universal_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f), SEX_BOTH)); + addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha", "", "", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", "", "", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + addEntry(SUBPART_UNIVERSAL, new SubpartEntry(SUBPART_UNIVERSAL, "mPelvis", "universal", "", "", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f), SEX_BOTH)); // - addEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, "mTorso", "physics_breasts_updown", "physics_breasts_updown_param_list", "physics_breasts_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_FEMALE)); - addEntry(SUBPART_PHYSICS_BREASTS_INOUT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_INOUT, "mTorso", "physics_breasts_inout", "physics_breasts_inout_param_list", "physics_breasts_inout_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_FEMALE)); + + // WT_PHYSIC + addEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, "mTorso", "physics_breasts_updown", "physics_breasts_updown_param_list", "physics_breasts_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_FEMALE)); + addEntry(SUBPART_PHYSICS_BREASTS_INOUT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_INOUT, "mTorso", "physics_breasts_inout", "physics_breasts_inout_param_list", "physics_breasts_inout_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_FEMALE)); addEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, "mTorso", "physics_breasts_leftright", "physics_breasts_leftright_param_list", "physics_breasts_leftright_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_FEMALE)); // Fix XUI warning - //addEntry(SUBPART_PHYSICS_BELLY_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BELLY_UPDOWN, "mTorso", "physics_belly_updown", "physics_belly_updown_param_list", "physics_belly_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); - //addEntry(SUBPART_PHYSICS_BUTT_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BUTT_UPDOWN, "mTorso", "physics_butt_updown", "physics_butt_updown_param_list", "physics_butt_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); - addEntry(SUBPART_PHYSICS_BELLY_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BELLY_UPDOWN, "mTorso", "physics_belly_updown", "physics_belly_updown_param_list", "physics_belly_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); - addEntry(SUBPART_PHYSICS_BUTT_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BUTT_UPDOWN, "mTorso", "physics_butt_updown", "physics_butt_updown_param_list", "physics_butt_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); + //addEntry(SUBPART_PHYSICS_BELLY_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BELLY_UPDOWN, "mTorso", "physics_belly_updown", "physics_belly_updown_param_list", "physics_belly_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); + //addEntry(SUBPART_PHYSICS_BUTT_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BUTT_UPDOWN, "mTorso", "physics_butt_updown", "physics_butt_updown_param_list", "physics_butt_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BELLY_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BELLY_UPDOWN, "mTorso", "physics_belly_updown", "physics_belly_updown_param_list", "physics_belly_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BUTT_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BUTT_UPDOWN, "mTorso", "physics_butt_updown", "physics_butt_updown_param_list", "physics_butt_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); // - addEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, "mTorso", "physics_butt_leftright", "physics_butt_leftright_param_list", "physics_butt_leftright_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); - addEntry(SUBPART_PHYSICS_ADVANCED, new SubpartEntry(SUBPART_PHYSICS_ADVANCED, "mTorso", "physics_advanced", "physics_advanced_param_list", "physics_advanced_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, "mTorso", "physics_butt_leftright", "physics_butt_leftright_param_list", "physics_butt_leftright_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_ADVANCED, new SubpartEntry(SUBPART_PHYSICS_ADVANCED, "mTorso", "physics_advanced", "physics_advanced_param_list", "physics_advanced_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH)); } LLEditWearableDictionary::SubpartEntry::SubpartEntry(ESubpart part, @@ -342,55 +349,55 @@ LLEditWearableDictionary::SubpartEntry::SubpartEntry(ESubpart part, LLEditWearableDictionary::ColorSwatchCtrls::ColorSwatchCtrls() { - addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Color/Tint" )); - addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Color/Tint" )); - addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Color/Tint" )); - addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Color/Tint" )); - addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Color/Tint" )); - addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Color/Tint" )); - addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Color/Tint" )); - addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Color/Tint" )); - addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Color/Tint" )); - addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry(TEX_HEAD_TATTOO, "Color/Tint" )); - addEntry (TEX_HEAD_UNIVERSAL_TATTOO, new PickerControlEntry(TEX_HEAD_UNIVERSAL_TATTOO, "Color/Tint")); + addEntry(TEX_UPPER_SHIRT, new PickerControlEntry(TEX_UPPER_SHIRT, "Color/Tint")); + addEntry(TEX_LOWER_PANTS, new PickerControlEntry(TEX_LOWER_PANTS, "Color/Tint")); + addEntry(TEX_LOWER_SHOES, new PickerControlEntry(TEX_LOWER_SHOES, "Color/Tint")); + addEntry(TEX_LOWER_SOCKS, new PickerControlEntry(TEX_LOWER_SOCKS, "Color/Tint")); + addEntry(TEX_UPPER_JACKET, new PickerControlEntry(TEX_UPPER_JACKET, "Color/Tint")); + addEntry(TEX_SKIRT, new PickerControlEntry(TEX_SKIRT, "Color/Tint")); + addEntry(TEX_UPPER_GLOVES, new PickerControlEntry(TEX_UPPER_GLOVES, "Color/Tint")); + addEntry(TEX_UPPER_UNDERSHIRT, new PickerControlEntry(TEX_UPPER_UNDERSHIRT, "Color/Tint")); + addEntry(TEX_LOWER_UNDERPANTS, new PickerControlEntry(TEX_LOWER_UNDERPANTS, "Color/Tint")); + addEntry(TEX_HEAD_TATTOO, new PickerControlEntry(TEX_HEAD_TATTOO, "Color/Tint")); + addEntry(TEX_HEAD_UNIVERSAL_TATTOO, new PickerControlEntry(TEX_HEAD_UNIVERSAL_TATTOO, "Color/Tint")); } LLEditWearableDictionary::TextureCtrls::TextureCtrls() { - addEntry ( TEX_HEAD_BODYPAINT, new PickerControlEntry (TEX_HEAD_BODYPAINT, "Head", LLUUID::null, TRUE )); - addEntry ( TEX_UPPER_BODYPAINT, new PickerControlEntry (TEX_UPPER_BODYPAINT, "Upper Body", LLUUID::null, TRUE )); - addEntry ( TEX_LOWER_BODYPAINT, new PickerControlEntry (TEX_LOWER_BODYPAINT, "Lower Body", LLUUID::null, TRUE )); - addEntry ( TEX_HAIR, new PickerControlEntry (TEX_HAIR, "Texture", LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), FALSE )); - addEntry ( TEX_EYES_IRIS, new PickerControlEntry (TEX_EYES_IRIS, "Iris", LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), FALSE )); - addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), FALSE )); - addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Upper Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_JACKET, new PickerControlEntry (TEX_LOWER_JACKET, "Lower Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); - addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), FALSE )); - addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), FALSE )); - addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); - addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); - addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); - addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); - addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); - addEntry ( TEX_LOWER_TATTOO, new PickerControlEntry (TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE )); - addEntry ( TEX_UPPER_TATTOO, new PickerControlEntry (TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE )); - addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry (TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE )); - addEntry ( TEX_LOWER_UNIVERSAL_TATTOO, new PickerControlEntry( TEX_LOWER_UNIVERSAL_TATTOO, "Lower Universal Tattoo", LLUUID::null, TRUE)); - addEntry ( TEX_UPPER_UNIVERSAL_TATTOO, new PickerControlEntry( TEX_UPPER_UNIVERSAL_TATTOO, "Upper Universal Tattoo", LLUUID::null, TRUE)); - addEntry ( TEX_HEAD_UNIVERSAL_TATTOO, new PickerControlEntry( TEX_HEAD_UNIVERSAL_TATTOO, "Head Universal Tattoo", LLUUID::null, TRUE)); - addEntry ( TEX_SKIRT_TATTOO, new PickerControlEntry(TEX_SKIRT_TATTOO, "Skirt Tattoo", LLUUID::null, TRUE)); - addEntry ( TEX_HAIR_TATTOO, new PickerControlEntry(TEX_HAIR_TATTOO, "Hair Tattoo", LLUUID::null, TRUE)); - addEntry ( TEX_EYES_TATTOO, new PickerControlEntry(TEX_EYES_TATTOO, "Eyes Tattoo", LLUUID::null, TRUE)); - addEntry (TEX_LEFT_ARM_TATTOO, new PickerControlEntry(TEX_LEFT_ARM_TATTOO, "Left Arm Tattoo", LLUUID::null, TRUE)); - addEntry (TEX_LEFT_LEG_TATTOO, new PickerControlEntry(TEX_LEFT_LEG_TATTOO, "Left Leg Tattoo", LLUUID::null, TRUE)); - addEntry (TEX_AUX1_TATTOO, new PickerControlEntry(TEX_AUX1_TATTOO, "Aux1 Tattoo", LLUUID::null, TRUE)); - addEntry (TEX_AUX2_TATTOO, new PickerControlEntry(TEX_AUX2_TATTOO, "Aux2 Tattoo", LLUUID::null, TRUE)); - addEntry (TEX_AUX3_TATTOO, new PickerControlEntry(TEX_AUX3_TATTOO, "Aux3 Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_HEAD_BODYPAINT, new PickerControlEntry(TEX_HEAD_BODYPAINT, "Head", LLUUID::null, TRUE)); + addEntry(TEX_UPPER_BODYPAINT, new PickerControlEntry(TEX_UPPER_BODYPAINT, "Upper Body", LLUUID::null, TRUE)); + addEntry(TEX_LOWER_BODYPAINT, new PickerControlEntry(TEX_LOWER_BODYPAINT, "Lower Body", LLUUID::null, TRUE)); + addEntry(TEX_HAIR, new PickerControlEntry(TEX_HAIR, "Texture", LLUUID(gSavedSettings.getString("UIImgDefaultHairUUID")), FALSE)); + addEntry(TEX_EYES_IRIS, new PickerControlEntry(TEX_EYES_IRIS, "Iris", LLUUID(gSavedSettings.getString("UIImgDefaultEyesUUID")), FALSE)); + addEntry(TEX_UPPER_SHIRT, new PickerControlEntry(TEX_UPPER_SHIRT, "Fabric", LLUUID(gSavedSettings.getString("UIImgDefaultShirtUUID")), FALSE)); + addEntry(TEX_LOWER_PANTS, new PickerControlEntry(TEX_LOWER_PANTS, "Fabric", LLUUID(gSavedSettings.getString("UIImgDefaultPantsUUID")), FALSE)); + addEntry(TEX_LOWER_SHOES, new PickerControlEntry(TEX_LOWER_SHOES, "Fabric", LLUUID(gSavedSettings.getString("UIImgDefaultShoesUUID")), FALSE)); + addEntry(TEX_LOWER_SOCKS, new PickerControlEntry(TEX_LOWER_SOCKS, "Fabric", LLUUID(gSavedSettings.getString("UIImgDefaultSocksUUID")), FALSE)); + addEntry(TEX_UPPER_JACKET, new PickerControlEntry(TEX_UPPER_JACKET, "Upper Fabric", LLUUID(gSavedSettings.getString("UIImgDefaultJacketUUID")), FALSE)); + addEntry(TEX_LOWER_JACKET, new PickerControlEntry(TEX_LOWER_JACKET, "Lower Fabric", LLUUID(gSavedSettings.getString("UIImgDefaultJacketUUID")), FALSE)); + addEntry(TEX_SKIRT, new PickerControlEntry(TEX_SKIRT, "Fabric", LLUUID(gSavedSettings.getString("UIImgDefaultSkirtUUID")), FALSE)); + addEntry(TEX_UPPER_GLOVES, new PickerControlEntry(TEX_UPPER_GLOVES, "Fabric", LLUUID(gSavedSettings.getString("UIImgDefaultGlovesUUID")), FALSE)); + addEntry(TEX_UPPER_UNDERSHIRT, new PickerControlEntry(TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID(gSavedSettings.getString("UIImgDefaultUnderwearUUID")), FALSE)); + addEntry(TEX_LOWER_UNDERPANTS, new PickerControlEntry(TEX_LOWER_UNDERPANTS, "Fabric", LLUUID(gSavedSettings.getString("UIImgDefaultUnderwearUUID")), FALSE)); + addEntry(TEX_LOWER_ALPHA, new PickerControlEntry(TEX_LOWER_ALPHA, "Lower Alpha", LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), TRUE)); + addEntry(TEX_UPPER_ALPHA, new PickerControlEntry(TEX_UPPER_ALPHA, "Upper Alpha", LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), TRUE)); + addEntry(TEX_HEAD_ALPHA, new PickerControlEntry(TEX_HEAD_ALPHA, "Head Alpha", LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), TRUE)); + addEntry(TEX_EYES_ALPHA, new PickerControlEntry(TEX_EYES_ALPHA, "Eye Alpha", LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), TRUE)); + addEntry(TEX_HAIR_ALPHA, new PickerControlEntry(TEX_HAIR_ALPHA, "Hair Alpha", LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), TRUE)); + addEntry(TEX_LOWER_TATTOO, new PickerControlEntry(TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_UPPER_TATTOO, new PickerControlEntry(TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_HEAD_TATTOO, new PickerControlEntry(TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_LOWER_UNIVERSAL_TATTOO, new PickerControlEntry(TEX_LOWER_UNIVERSAL_TATTOO, "Lower Universal Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_UPPER_UNIVERSAL_TATTOO, new PickerControlEntry(TEX_UPPER_UNIVERSAL_TATTOO, "Upper Universal Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_HEAD_UNIVERSAL_TATTOO, new PickerControlEntry(TEX_HEAD_UNIVERSAL_TATTOO, "Head Universal Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_SKIRT_TATTOO, new PickerControlEntry(TEX_SKIRT_TATTOO, "Skirt Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_HAIR_TATTOO, new PickerControlEntry(TEX_HAIR_TATTOO, "Hair Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_EYES_TATTOO, new PickerControlEntry(TEX_EYES_TATTOO, "Eyes Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_LEFT_ARM_TATTOO, new PickerControlEntry(TEX_LEFT_ARM_TATTOO, "Left Arm Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_LEFT_LEG_TATTOO, new PickerControlEntry(TEX_LEFT_LEG_TATTOO, "Left Leg Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_AUX1_TATTOO, new PickerControlEntry(TEX_AUX1_TATTOO, "Aux1 Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_AUX2_TATTOO, new PickerControlEntry(TEX_AUX2_TATTOO, "Aux2 Tattoo", LLUUID::null, TRUE)); + addEntry(TEX_AUX3_TATTOO, new PickerControlEntry(TEX_AUX3_TATTOO, "Aux3 Tattoo", LLUUID::null, TRUE)); } LLEditWearableDictionary::PickerControlEntry::PickerControlEntry(ETextureIndex tex_index, @@ -503,8 +510,8 @@ template const LLEditWearableDictionary::PickerControlEntry* find_picker_ctrl_entry_if(LLWearableType::EType type, const Predicate pred) { - const LLEditWearableDictionary::WearableEntry *wearable_entry - = LLEditWearableDictionary::getInstance()->getWearable(type); + const LLEditWearableDictionary::WearableEntry *wearable_entry = + LLEditWearableDictionary::getInstance()->getWearable(type); if (!wearable_entry) { LL_WARNS() << "could not get wearable dictionary entry for wearable of type: " << type << LL_ENDL; @@ -533,8 +540,7 @@ find_picker_ctrl_entry_if(LLWearableType::EType type, const Predicate pred) } template -void -for_each_picker_ctrl_entry(LLPanel* panel, LLWearableType::EType type, function_t fun) +void for_each_picker_ctrl_entry(LLPanel* panel, LLWearableType::EType type, function_t fun) { if (!panel) { @@ -555,14 +561,13 @@ for_each_picker_ctrl_entry(LLPanel* panel, LLWearableType::EType type, function_ iter != iter_end; ++iter) { const ETextureIndex te = *iter; - const LLEditWearableDictionary::PickerControlEntry* entry - = get_picker_entry(te); + const LLEditWearableDictionary::PickerControlEntry* entry = get_picker_entry(te); if (!entry) { LL_WARNS() << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << LL_ENDL; continue; } - fun (panel, entry); + fun(panel, entry); } } @@ -607,7 +612,7 @@ static void update_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const { LLUUID new_id; LLLocalTextureObject *lto = self->getWearable()->getLocalTextureObject(entry->mTextureIndex); - if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) ) + if (lto && (lto->getID() != IMG_DEFAULT_AVATAR)) { new_id = lto->getID(); } @@ -776,7 +781,7 @@ BOOL LLPanelEditWearable::postBuild() mPanelSkirt = getChild("edit_skirt_panel"); mPanelAlpha = getChild("edit_alpha_panel"); mPanelTattoo = getChild("edit_tattoo_panel"); - mPanelUniversal = getChild("edit_universal_panel"); + mPanelUniversal = getChild("edit_universal_panel"); mPanelPhysics = getChild("edit_physics_panel"); mTxtAvatarHeight = mPanelShape->getChild("avatar_height"); @@ -803,19 +808,19 @@ BOOL LLPanelEditWearable::postBuild() // Appearance panel not updating camera position bool tab_container_cb_set = false; - + for (U8 index = 0; index < num_subparts; ++index) { // dive into data structures to get the panel we need ESubpart subpart_e = wearable_entry->mSubparts[index]; const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); - + if (!subpart_entry) { LL_WARNS() << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << LL_ENDL; continue; } - + const std::string accordion_tab = subpart_entry->mAccordionTab; // Alpha and tattoo don't adhere to the usual panel layout and don't have a param list and main tab @@ -828,13 +833,13 @@ BOOL LLPanelEditWearable::postBuild() } LLAccordionCtrlTab *tab = findChild(accordion_tab); // - + if (!tab) { LL_WARNS() << "could not get llaccordionctrltab from UI with name: " << accordion_tab << LL_ENDL; continue; } - + // initialize callback to ensure camera view changes appropriately. tab->setDropDownStateChangedCallback(boost::bind(&LLPanelEditWearable::onTabExpandedCollapsed,this,_2,index)); @@ -881,14 +886,16 @@ BOOL LLPanelEditWearable::isDirty() const BOOL isDirty = FALSE; if (mWearablePtr) { - if (mWearablePtr->isDirty() || - ( mWearableItem && mNameEditor && mWearableItem->getName().compare(mNameEditor->getText()) != 0 )) - { - isDirty = TRUE; - } + if (mWearablePtr->isDirty() || + (mWearableItem && mNameEditor && mWearableItem->getName().compare(mNameEditor->getText()) != 0)) + { + isDirty = TRUE; + } } return isDirty; } + + //virtual void LLPanelEditWearable::draw() { @@ -904,8 +911,8 @@ void LLPanelEditWearable::draw() void LLPanelEditWearable::onClose() { - // any unsaved changes should be reverted at this point - revertChanges(); + // any unsaved changes should be reverted at this point + revertChanges(); } void LLPanelEditWearable::setVisible(BOOL visible) @@ -922,7 +929,7 @@ void LLPanelEditWearable::setWearable(LLViewerWearable *wearable, BOOL disable_c showWearable(mWearablePtr, FALSE, disable_camera_switch); if (mWearablePtr) mWearablePtr->unregisterObserver(this); - mWearablePtr = wearable; + mWearablePtr = wearable; if( mWearablePtr ) mWearablePtr->registerObserver( this ); showWearable(mWearablePtr, TRUE, disable_camera_switch); @@ -931,11 +938,11 @@ void LLPanelEditWearable::setWearable(LLViewerWearable *wearable, BOOL disable_c //static void LLPanelEditWearable::onBackButtonClicked(void* userdata) { - LLPanelEditWearable *panel = (LLPanelEditWearable*) userdata; - if ( panel->isDirty() ) - { - LLAppearanceMgr::instance().setOutfitDirty( true ); - } + LLPanelEditWearable* panel = (LLPanelEditWearable*)userdata; + if (panel->isDirty()) + { + LLAppearanceMgr::instance().setOutfitDirty(true); + } } //static @@ -960,7 +967,7 @@ void LLPanelEditWearable::saveAsCallback(const LLSD& notification, const LLSD& r { std::string wearable_name = response["message"].asString(); LLStringUtil::trim(wearable_name); - if( !wearable_name.empty() ) + if (!wearable_name.empty()) { mNameEditor->setText(wearable_name); saveChanges(true); @@ -970,24 +977,27 @@ void LLPanelEditWearable::saveAsCallback(const LLSD& notification, const LLSD& r void LLPanelEditWearable::onCommitSexChange() { - if (!isAgentAvatarValid()) return; + if (!isAgentAvatarValid()) + { + return; + } LLWearableType::EType type = mWearablePtr->getType(); U32 index; - if( !gAgentWearables.getWearableIndex(mWearablePtr, index) || - !gAgentWearables.isWearableModifiable(type, index)) + if (!gAgentWearables.getWearableIndex(mWearablePtr, index) || + !gAgentWearables.isWearableModifiable(type, index)) { - return; + return; } LLViewerVisualParam* param = static_cast(gAgentAvatarp->getVisualParam( "male" )); - if( !param ) + if (!param) { - return; + return; } bool is_new_sex_male = (gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE) == SEX_MALE; - LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, index); + LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, index); if (wearable) { // [Legacy Bake] @@ -1027,25 +1037,25 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) { // Set the new version LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_ctrl->getImageAssetID()); - if( image->getID() == IMG_DEFAULT ) + if (image->getID() == IMG_DEFAULT) { image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); } if (getWearable()) { - U32 index; - if (gAgentWearables.getWearableIndex(getWearable(), index)) - { - gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index); - LLVisualParamHint::requestHintUpdates(); - // [Legacy Bake] - //gAgentAvatarp->wearableUpdated(type); - gAgentAvatarp->wearableUpdated(type, FALSE); - } - else - { - LL_WARNS() << "wearable not found in gAgentWearables" << LL_ENDL; - } + U32 index; + if (gAgentWearables.getWearableIndex(getWearable(), index)) + { + gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index); + LLVisualParamHint::requestHintUpdates(); + // [Legacy Bake] + //gAgentAvatarp->wearableUpdated(type); + gAgentAvatarp->wearableUpdated(type, FALSE); + } + else + { + LL_WARNS() << "wearable not found in gAgentWearables" << LL_ENDL; + } } } else @@ -1061,13 +1071,13 @@ void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* ctrl) { LLWearableType::EType type = getWearable()->getType(); const PickerControlEntryNamePredicate name_pred(ctrl->getName()); - const LLEditWearableDictionary::PickerControlEntry* entry - = find_picker_ctrl_entry_if(type, name_pred); + const LLEditWearableDictionary::PickerControlEntry* entry = + find_picker_ctrl_entry_if(type, name_pred); if (entry) { const LLColor4& old_color = getWearable()->getClothesColor(entry->mTextureIndex); const LLColor4& new_color = LLColor4(ctrl->getValue()); - if( old_color != new_color ) + if (old_color != new_color) { // [Legacy Bake] //getWearable()->setClothesColor(entry->mTextureIndex, new_color); @@ -1089,11 +1099,13 @@ void LLPanelEditWearable::updatePanelPickerControls(LLWearableType::EType type) { LLPanel* panel = getPanel(type); if (!panel) + { return; + } bool is_modifiable = false; - if(mWearableItem) + if (mWearableItem) { const LLPermissions& perm = mWearableItem->getPermissions(); is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); @@ -1115,7 +1127,6 @@ void LLPanelEditWearable::updatePanelPickerControls(LLWearableType::EType type) void LLPanelEditWearable::incrementCofVersionLegacy() { - } void LLPanelEditWearable::saveChanges(bool force_save_as) @@ -1127,61 +1138,59 @@ void LLPanelEditWearable::saveChanges(bool force_save_as) } U32 index; - if (!gAgentWearables.getWearableIndex(mWearablePtr, index)) - { - LL_WARNS() << "wearable not found" << LL_ENDL; - return; - } + if (!gAgentWearables.getWearableIndex(mWearablePtr, index)) + { + LL_WARNS() << "wearable not found" << LL_ENDL; + return; + } std::string new_name = mNameEditor->getText(); - // Find an existing link to this wearable's inventory item, if any, and its description field. - LLInventoryItem *link_item = NULL; - std::string description; - LLInventoryModel::item_array_t links = - LLAppearanceMgr::instance().findCOFItemLinks(mWearablePtr->getItemID()); - if (links.size()>0) - { - link_item = links.at(0).get(); - if (link_item && link_item->getIsLinkType()) - { - description = link_item->getActualDescription(); - } - } + // Find an existing link to this wearable's inventory item, if any, and its description field. + LLInventoryItem* link_item = NULL; + std::string description; + LLInventoryModel::item_array_t links = + LLAppearanceMgr::instance().findCOFItemLinks(mWearablePtr->getItemID()); + if (links.size() > 0) + { + link_item = links.at(0).get(); + if (link_item && link_item->getIsLinkType()) + { + description = link_item->getActualDescription(); + } + } if (force_save_as) { - // the name of the wearable has changed, re-save wearable with new name - LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID(),gAgentAvatarp->mEndCustomizeCallback); - gAgentWearables.saveWearableAs(mWearablePtr->getType(), index, new_name, description, FALSE); - mNameEditor->setText(mWearableItem->getName()); + // the name of the wearable has changed, re-save wearable with new name + LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID(), gAgentAvatarp->mEndCustomizeCallback); + gAgentWearables.saveWearableAs(mWearablePtr->getType(), index, new_name, description, FALSE); + mNameEditor->setText(mWearableItem->getName()); } else { - // Make another copy of this link, with the same - // description. This is needed to bump the COF - // version so texture baking service knows appearance has changed. - if (link_item) - { - // Create new link - LL_DEBUGS("Avatar") << "link refresh, creating new link to " << link_item->getLinkedUUID() - << " removing old link at " << link_item->getUUID() - << " wearable item id " << mWearablePtr->getItemID() << LL_ENDL; + // Make another copy of this link, with the same + // description. This is needed to bump the COF + // version so texture baking service knows appearance has changed. + if (link_item) + { + // Create new link + LL_DEBUGS("Avatar") << "link refresh, creating new link to " << link_item->getLinkedUUID() + << " removing old link at " << link_item->getUUID() + << " wearable item id " << mWearablePtr->getItemID() << LL_ENDL; - LLInventoryObject::const_object_list_t obj_array; - obj_array.push_back(LLConstPointer(link_item)); - link_inventory_array(LLAppearanceMgr::instance().getCOF(), - obj_array, - gAgentAvatarp->mEndCustomizeCallback); - // Remove old link - remove_inventory_item(link_item->getUUID(), gAgentAvatarp->mEndCustomizeCallback); - } - // [Legacy Bake] - //gAgentWearables.saveWearable(mWearablePtr->getType(), index, new_name); - gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name); + LLInventoryObject::const_object_list_t obj_array; + obj_array.push_back(LLConstPointer(link_item)); + link_inventory_array(LLAppearanceMgr::instance().getCOF(), + obj_array, + gAgentAvatarp->mEndCustomizeCallback); + // Remove old link + remove_inventory_item(link_item->getUUID(), gAgentAvatarp->mEndCustomizeCallback); + } + // [Legacy Bake] + //gAgentWearables.saveWearable(mWearablePtr->getType(), index, new_name); + gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name); } - - } void LLPanelEditWearable::revertChanges() @@ -1233,15 +1242,15 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO targetPanel->setVisible(show); toggleTypeSpecificControls(type); - // Update type controls here - updateTypeSpecificControls(type); + // Update type controls here + updateTypeSpecificControls(type); if (show) { mPanelTitle->setText(title); mPanelTitle->setToolTip(title); mDescTitle->setText(description_title); - + // set name mNameEditor->setText(mWearableItem->getName()); @@ -1249,19 +1258,19 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO // clear and rebuild visual param list U8 num_subparts = (U8)(wearable_entry->mSubparts.size()); - + for (U8 index = 0; index < num_subparts; ++index) { // dive into data structures to get the panel we need ESubpart subpart_e = wearable_entry->mSubparts[index]; const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); - + if (!subpart_entry) { LL_WARNS() << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << LL_ENDL; continue; } - + const std::string scrolling_panel = subpart_entry->mParamList; const std::string accordion_tab = subpart_entry->mAccordionTab; @@ -1275,51 +1284,52 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO LLScrollingPanelList *panel_list = getChild(scrolling_panel); LLAccordionCtrlTab *tab = getChild(accordion_tab); - + if (!panel_list) { LL_WARNS() << "could not get scrolling panel list: " << scrolling_panel << LL_ENDL; continue; } - + if (!tab) { LL_WARNS() << "could not get llaccordionctrltab from UI with name: " << accordion_tab << LL_ENDL; continue; } - // Don't show female subparts if you're not female, etc. - if (!(gAgentAvatarp->getSex() & subpart_entry->mSex)) - { - tab->setVisible(FALSE); - continue; - } - else - { - tab->setVisible(TRUE); - } - + // Don't show female subparts if you're not female, etc. + if (!(gAgentAvatarp->getSex() & subpart_entry->mSex)) + { + tab->setVisible(FALSE); + continue; + } + else + { + tab->setVisible(TRUE); + } + // what edit group do we want to extract params for? const std::string edit_group = subpart_entry->mEditGroup; - + // storage for ordered list of visual params value_map_t sorted_params; getSortedParams(sorted_params, edit_group); -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// LLJoint* jointp = gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ); - LLJoint* jointp = gAgentAvatarp->getJoint( JointKey::construct( subpart_entry->mTargetJoint ) ); - if( !jointp ) + // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup + //LLJoint* jointp = gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ); + LLJoint* jointp = gAgentAvatarp->getJoint( JointKey::construct( subpart_entry->mTargetJoint ) ); + if (!jointp) { -// jointp = gAgentAvatarp->getJoint( "mHead" ); - jointp = gAgentAvatarp->getJoint( JointKey::construct( "mHead" ) ); - } -// + //jointp = gAgentAvatarp->getJoint( "mHead" ); + jointp = gAgentAvatarp->getJoint( JointKey::construct( "mHead" ) ); + } + // buildParamList(panel_list, sorted_params, tab, jointp); - + updateScrollingPanelUI(); } + if (!disable_camera_switch) { showDefaultSubpart(); @@ -1357,55 +1367,55 @@ void LLPanelEditWearable::onTabExpandedCollapsed(const LLSD& param, U8 index) mLastShownSubpartIndex[mWearablePtr->getType()] = index; // Correct camera position for last subpart changeCamera(index); } - } // Appearance panel not updating camera position void LLPanelEditWearable::onTabChanged(LLUICtrl* ctrl, LLWearableType::EType type) { - LLTabContainer* container = dynamic_cast(ctrl); - if (!container) - { - return; - } + LLTabContainer* container = dynamic_cast(ctrl); + if (!container) + { + return; + } - if (!mWearablePtr || !gAgentCamera.cameraCustomizeAvatar()) - { - // we don't have a valid wearable we're editing, or we've left the wearable editor - return; - } + if (!mWearablePtr || !gAgentCamera.cameraCustomizeAvatar()) + { + // we don't have a valid wearable we're editing, or we've left the wearable editor + return; + } - const LLEditWearableDictionary::WearableEntry* wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type); - if (!wearable_entry) - { - return; - } + const LLEditWearableDictionary::WearableEntry* wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type); + if (!wearable_entry) + { + return; + } - llassert_always(wearable_entry->mSubparts.size() <= 0xFF); - U8 num_subparts = static_cast(wearable_entry->mSubparts.size()); - for (U8 index = 0; index < num_subparts; ++index) - { - ESubpart subpart_e = wearable_entry->mSubparts[index]; - const LLEditWearableDictionary::SubpartEntry* subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + llassert_always(wearable_entry->mSubparts.size() <= 0xFF); + U8 num_subparts = static_cast(wearable_entry->mSubparts.size()); + for (U8 index = 0; index < num_subparts; ++index) + { + ESubpart subpart_e = wearable_entry->mSubparts[index]; + const LLEditWearableDictionary::SubpartEntry* subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); - if (subpart_entry && container->getCurrentPanel()->hasChild(subpart_entry->mAccordionTab, TRUE)) - { - mLastShownSubpartIndex[type] = index; // Correct camera position for last subpart - changeCamera(index); - break; - } - } + if (subpart_entry && container->getCurrentPanel()->hasChild(subpart_entry->mAccordionTab, TRUE)) + { + mLastShownSubpartIndex[type] = index; // Correct camera position for last subpart + changeCamera(index); + break; + } + } } // void LLPanelEditWearable::changeCamera(U8 subpart) { - // Don't change the camera if this type doesn't have a camera switch. - // Useful for wearables like physics that don't have an associated physical body part. - if (LLWearableType::getInstance()->getDisableCameraSwitch(mWearablePtr->getType())) - { - return; - } + // Don't change the camera if this type doesn't have a camera switch. + // Useful for wearables like physics that don't have an associated physical body part. + if (LLWearableType::getInstance()->getDisableCameraSwitch(mWearablePtr->getType())) + { + return; + } + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mWearablePtr->getType()); if (!wearable_entry) { @@ -1438,9 +1448,9 @@ void LLPanelEditWearable::changeCamera(U8 subpart) gMorphView->setCameraOffset( subpart_entry->mCameraOffset ); if (gSavedSettings.getBOOL("AppearanceCameraMovement")) { - // Unlock focus from avatar but don't stop animation to not interrupt ANIM_AGENT_CUSTOMIZE - gAgentCamera.setFocusOnAvatar(FALSE, gAgentCamera.getCameraAnimating()); - gMorphView->updateCamera(); + // Unlock focus from avatar but don't stop animation to not interrupt ANIM_AGENT_CUSTOMIZE + gAgentCamera.setFocusOnAvatar(FALSE, gAgentCamera.getCameraAnimating()); + gMorphView->updateCamera(); } } @@ -1468,10 +1478,9 @@ void LLPanelEditWearable::updateTypeSpecificControls(LLWearableType::EType type) if (type == LLWearableType::WT_SHAPE) { // Update avatar height - // The .195 is a fudge factor derived by measuring against - // prims inworld, and carried forward from Phoenix. -- TS - F32 new_size = gAgentAvatarp->mBodySize.mV[VZ] + .195f; - + // The .195 is a fudge factor derived by measuring against + // prims inworld, and carried forward from Phoenix. -- TS + F32 new_size = gAgentAvatarp->mBodySize.mV[VZ] + .195f; if (gSavedSettings.getBOOL("HeightUnits") == FALSE) { // convert meters to feet @@ -1502,14 +1511,18 @@ void LLPanelEditWearable::updateScrollingPanelUI() LLWearableType::EType type = mWearablePtr->getType(); LLPanel *panel = getPanel(type); - if(panel && (mWearablePtr->getItemID().notNull())) + if (panel && (mWearablePtr->getItemID().notNull())) { const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type); llassert(wearable_entry); - if (!wearable_entry) return; - U8 num_subparts = (U8)(wearable_entry->mSubparts.size()); + if (!wearable_entry) + { + return; + } LLScrollingPanelParam::sUpdateDelayFrames = 0; + + U8 num_subparts = (U8)(wearable_entry->mSubparts.size()); for (U8 index = 0; index < num_subparts; ++index) { // dive into data structures to get the panel we need @@ -1519,13 +1532,13 @@ void LLPanelEditWearable::updateScrollingPanelUI() const std::string scrolling_panel = subpart_entry->mParamList; LLScrollingPanelList *panel_list = getChild(scrolling_panel); - + if (!panel_list) { LL_WARNS() << "could not get scrolling panel list: " << scrolling_panel << LL_ENDL; continue; } - + panel_list->updatePanels(TRUE); } } @@ -1537,76 +1550,58 @@ LLPanel* LLPanelEditWearable::getPanel(LLWearableType::EType type) { case LLWearableType::WT_SHAPE: return mPanelShape; - break; case LLWearableType::WT_SKIN: return mPanelSkin; - break; case LLWearableType::WT_HAIR: return mPanelHair; - break; case LLWearableType::WT_EYES: return mPanelEyes; - break; case LLWearableType::WT_SHIRT: return mPanelShirt; - break; case LLWearableType::WT_PANTS: return mPanelPants; - break; case LLWearableType::WT_SHOES: return mPanelShoes; - break; case LLWearableType::WT_SOCKS: return mPanelSocks; - break; case LLWearableType::WT_JACKET: return mPanelJacket; - break; case LLWearableType::WT_GLOVES: return mPanelGloves; - break; case LLWearableType::WT_UNDERSHIRT: return mPanelUndershirt; - break; case LLWearableType::WT_UNDERPANTS: return mPanelUnderpants; - break; case LLWearableType::WT_SKIRT: return mPanelSkirt; - break; case LLWearableType::WT_ALPHA: return mPanelAlpha; - break; case LLWearableType::WT_TATTOO: return mPanelTattoo; - break; - - case LLWearableType::WT_UNIVERSAL: - return mPanelUniversal; - break; + + case LLWearableType::WT_UNIVERSAL: + return mPanelUniversal; case LLWearableType::WT_PHYSICS: return mPanelPhysics; - break; default: - break; + return NULL; } - return NULL; } void LLPanelEditWearable::getSortedParams(value_map_t &sorted_params, const std::string &edit_group) @@ -1644,11 +1639,11 @@ void LLPanelEditWearable::buildParamList(LLScrollingPanelList *panel_list, value // sorted_params is sorted according to magnitude of effect from // least to greatest. Adding to the front of the child list // reverses that order. - if( panel_list ) + if (panel_list) { panel_list->clearPanels(); value_map_t::iterator end = sorted_params.end(); - for(value_map_t::iterator it = sorted_params.begin(); it != end; ++it) + for (value_map_t::iterator it = sorted_params.begin(); it != end; ++it) { LLPanel::Params p; p.name("LLScrollingPanelParam"); @@ -1674,7 +1669,7 @@ void LLPanelEditWearable::updateVerbs() { bool can_copy = false; - if(mWearableItem) + if (mWearableItem) { can_copy = mWearableItem->getPermissions().allowCopyBy(gAgentID); } @@ -1688,7 +1683,7 @@ void LLPanelEditWearable::updateVerbs() // no modify, but what the hell, check anyways. childSetEnabled("import_btn", mWearableItem->getPermissions().allowModifyBy(gAgentID)); - if(isAgentAvatarValid()) + if (isAgentAvatarValid()) { // Update viewer's radio buttons (of RadioGroup with control_name="AvatarSex") of Avatar's gender // with value from "AvatarSex" setting @@ -1729,17 +1724,20 @@ void LLPanelEditWearable::configureAlphaCheckbox(LLAvatarAppearanceDefines::ETex void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLAvatarAppearanceDefines::ETextureIndex te) { - if (!checkbox_ctrl) return; - if (!getWearable()) return; + if (!checkbox_ctrl || !getWearable()) + { + return; + } LL_INFOS() << "onInvisibilityCommit, self " << this << " checkbox_ctrl " << checkbox_ctrl << LL_ENDL; - U32 index; - if (!gAgentWearables.getWearableIndex(getWearable(),index)) - { - LL_WARNS() << "wearable not found" << LL_ENDL; - return; - } + U32 index; + if (!gAgentWearables.getWearableIndex(getWearable(), index)) + { + LL_WARNS() << "wearable not found" << LL_ENDL; + return; + } + bool new_invis_state = checkbox_ctrl->get(); if (new_invis_state) { @@ -1747,10 +1745,10 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL mPreviousAlphaTexture[te] = lto->getID(); LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE ); - gAgentAvatarp->setLocalTexture(te, image, FALSE, index); - // [Legacy Bake] - //gAgentAvatarp->wearableUpdated(getWearable()->getType()); - gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + gAgentAvatarp->setLocalTexture(te, image, FALSE, index); + // [Legacy Bake] + //gAgentAvatarp->wearableUpdated(getWearable()->getType()); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); } else { @@ -1760,10 +1758,16 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL { prev_id = LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ); } - if (prev_id.isNull()) return; - + if (prev_id.isNull()) + { + return; + } + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); - if (!image) return; + if (!image) + { + return; + } gAgentAvatarp->setLocalTexture(te, image, FALSE, index); // [Legacy Bake] @@ -1776,7 +1780,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL void LLPanelEditWearable::updateAlphaCheckboxes() { - for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + for (string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); iter != mAlphaCheckbox2Index.end(); ++iter ) { LLAvatarAppearanceDefines::ETextureIndex te = (LLAvatarAppearanceDefines::ETextureIndex)iter->second; @@ -1814,76 +1818,76 @@ void LLPanelEditWearable::onClickedImportBtn() void LLPanelEditWearable::onClickedImportBtnCallback(const std::vector& filenames) { - const std::string filename = filenames[0]; - LLXmlTree tree; - if (!tree.parseFile(filename, FALSE)) - { - LL_WARNS("ShapeImport") << "Parsing " << filename << "failed miserably." << LL_ENDL; - LLNotificationsUtil::add("ShapeImportGenericFail", LLSD().with("FILENAME", filename)); - return; - } - LLXmlTreeNode* root = tree.getRoot(); - if (!root || !root->hasName("linden_genepool")) - { - LL_WARNS("ShapeImport") << filename << " has an invaid root node (not linden_genepool). Are you sure this is an avatar file?" << LL_ENDL; - LLNotificationsUtil::add("ShapeImportVersionFail", LLSD().with("FILENAME", filename)); - return; - } - std::string version; - static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); - if(!root->getFastAttributeString(version_string, version) || (version != "1.0") ) - { - LL_WARNS("ShapeImport") << "Invalid avatar file version: " << version << " in file: " << filename << LL_ENDL; - LLNotificationsUtil::add("ShapeImportVersionFail", LLSD().with("FILENAME", filename)); - return; - } - LLXmlTreeNode* archetype = root->getChildByName("archetype"); - if (archetype) - { - static const LLStdStringHandle id_handle = LLXmlTree::addAttributeString("id"); - static const LLStdStringHandle value_handle = LLXmlTree::addAttributeString("value"); - U32 parse_errors = 0; - - for (LLXmlTreeNode* child = archetype->getFirstChild(); child != NULL; child = archetype->getNextChild()) - { - if (!child->hasName("param")) continue; - S32 id; - F32 value; - std::string wearable; - if (child->getFastAttributeS32(id_handle, id) - && child->getFastAttributeF32(value_handle, value)) - { - LLVisualParam* visual_param = getWearable()->getVisualParam(id); - if (visual_param) - // [AIS Merge] Change back once legacy baking is re-added - //visual_param->setWeight(value); - visual_param->setWeight(value, FALSE); - } - else - { - LL_WARNS("ShapeImport") << "Failed to parse parameters in " << filename << LL_ENDL; - ++parse_errors; - } - } - if (parse_errors) - { - LLNotificationsUtil::add("ShapeImportGenericFail", LLSD().with("FILENAME", filename)); - } - if (isAgentAvatarValid()) - { - getWearable()->writeToAvatar(gAgentAvatarp); - gAgentAvatarp->updateVisualParams(); - updateScrollingPanelUI(); - LL_INFOS("ShapeImport") << "Shape import has finished with great success!" << LL_ENDL; - } - else - LL_WARNS("ShapeImport") << "Agent is not valid. Can't apply shape import changes" << LL_ENDL; - } - else - { - LL_WARNS("ShapeImport") << filename << " is missing the archetype." << LL_ENDL; - LLNotificationsUtil::add("ShapeImportGenericFail"); - } + const std::string filename = filenames[0]; + LLXmlTree tree; + if (!tree.parseFile(filename, FALSE)) + { + LL_WARNS("ShapeImport") << "Parsing " << filename << "failed miserably." << LL_ENDL; + LLNotificationsUtil::add("ShapeImportGenericFail", LLSD().with("FILENAME", filename)); + return; + } + LLXmlTreeNode* root = tree.getRoot(); + if (!root || !root->hasName("linden_genepool")) + { + LL_WARNS("ShapeImport") << filename << " has an invaid root node (not linden_genepool). Are you sure this is an avatar file?" << LL_ENDL; + LLNotificationsUtil::add("ShapeImportVersionFail", LLSD().with("FILENAME", filename)); + return; + } + std::string version; + static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); + if(!root->getFastAttributeString(version_string, version) || (version != "1.0") ) + { + LL_WARNS("ShapeImport") << "Invalid avatar file version: " << version << " in file: " << filename << LL_ENDL; + LLNotificationsUtil::add("ShapeImportVersionFail", LLSD().with("FILENAME", filename)); + return; + } + LLXmlTreeNode* archetype = root->getChildByName("archetype"); + if (archetype) + { + static const LLStdStringHandle id_handle = LLXmlTree::addAttributeString("id"); + static const LLStdStringHandle value_handle = LLXmlTree::addAttributeString("value"); + U32 parse_errors = 0; + + for (LLXmlTreeNode* child = archetype->getFirstChild(); child != NULL; child = archetype->getNextChild()) + { + if (!child->hasName("param")) continue; + S32 id; + F32 value; + std::string wearable; + if (child->getFastAttributeS32(id_handle, id) + && child->getFastAttributeF32(value_handle, value)) + { + LLVisualParam* visual_param = getWearable()->getVisualParam(id); + if (visual_param) + // [AIS Merge] Change back once legacy baking is re-added + //visual_param->setWeight(value); + visual_param->setWeight(value, FALSE); + } + else + { + LL_WARNS("ShapeImport") << "Failed to parse parameters in " << filename << LL_ENDL; + ++parse_errors; + } + } + if (parse_errors) + { + LLNotificationsUtil::add("ShapeImportGenericFail", LLSD().with("FILENAME", filename)); + } + if (isAgentAvatarValid()) + { + getWearable()->writeToAvatar(gAgentAvatarp); + gAgentAvatarp->updateVisualParams(); + updateScrollingPanelUI(); + LL_INFOS("ShapeImport") << "Shape import has finished with great success!" << LL_ENDL; + } + else + LL_WARNS("ShapeImport") << "Agent is not valid. Can't apply shape import changes" << LL_ENDL; + } + else + { + LL_WARNS("ShapeImport") << filename << " is missing the archetype." << LL_ENDL; + LLNotificationsUtil::add("ShapeImportGenericFail"); + } } // [/FS:CR] FIRE-10986 diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 91595ac8c6..b5f055b879 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -229,6 +229,17 @@ LLRender::eTexIndex LLPanelFace::getTextureDropChannel() return LLRender::eTexIndex(MATTYPE_DIFFUSE); } +LLGLTFMaterial::TextureInfo LLPanelFace::getPBRDropChannel() +{ + if (mComboMatMedia && mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR) + { + LLRadioGroup* radio_pbr_type = getChild("radio_pbr_type"); + return texture_info_from_pbrtype(radio_pbr_type->getSelectedIndex()); + } + + return texture_info_from_pbrtype(PBRTYPE_BASE_COLOR); +} + // Things the UI provides... // LLUUID LLPanelFace::getCurrentNormalMap() { return mBumpyTextureCtrl->getImageAssetID(); } @@ -428,13 +439,13 @@ BOOL LLPanelFace::postBuild() pbr_ctrl->setImmediateFilterPermMask(PERM_NONE); pbr_ctrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); pbr_ctrl->setBakeTextureEnabled(false); - pbr_ctrl->setInventoryPickType(LLTextureCtrl::PICK_MATERIAL); + pbr_ctrl->setInventoryPickType(PICK_MATERIAL); } mTextureCtrl = getChild("texture control"); if(mTextureCtrl) { - mTextureCtrl->setDefaultImageAssetID(LLUUID( gSavedSettings.getString( "DefaultObjectTexture" ))); + mTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_TEXTURE); mTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitTexture, this, _2) ); mTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelTexture, this, _2) ); mTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectTexture, this, _2) ); @@ -451,7 +462,7 @@ BOOL LLPanelFace::postBuild() mShinyTextureCtrl = getChild("shinytexture control"); if(mShinyTextureCtrl) { - mShinyTextureCtrl->setDefaultImageAssetID(LLUUID( gSavedSettings.getString( "DefaultObjectSpecularTexture" ))); + mShinyTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_SPECULAR); mShinyTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitSpecularTexture, this, _2) ); mShinyTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelSpecularTexture, this, _2) ); mShinyTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectSpecularTexture, this, _2) ); @@ -468,8 +479,8 @@ BOOL LLPanelFace::postBuild() mBumpyTextureCtrl = getChild("bumpytexture control"); if(mBumpyTextureCtrl) { - mBumpyTextureCtrl->setDefaultImageAssetID(LLUUID( gSavedSettings.getString( "DefaultObjectNormalTexture" ))); - mBumpyTextureCtrl->setBlankImageAssetID(LLUUID( gSavedSettings.getString( "DefaultBlankNormalTexture" ))); + mBumpyTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_NORMAL); + mBumpyTextureCtrl->setBlankImageAssetID(BLANK_OBJECT_NORMAL); mBumpyTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitNormalTexture, this, _2) ); mBumpyTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelNormalTexture, this, _2) ); mBumpyTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectNormalTexture, this, _2) ); @@ -592,6 +603,8 @@ LLPanelFace::LLPanelFace() mTitleMediaText(NULL), mNeedMediaTitle(true) { + buildFromFile("panel_tools_texture.xml"); // switchable edit texture/materials + USE_TEXTURE = LLTrans::getString("use_texture"); // Extended copy & paste buttons //mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", boost::bind(&LLPanelFace::menuDoToSelected, this, _2)); @@ -4597,7 +4610,7 @@ void LLPanelFace::onCopyTexture() LLUUID id = mat_data["NormMap"].asUUID(); if (id.notNull() && !get_can_copy_texture(id)) { - mat_data["NormMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + mat_data["NormMap"] = DEFAULT_OBJECT_TEXTURE; mat_data["NormMapNoCopy"] = true; } @@ -4607,7 +4620,7 @@ void LLPanelFace::onCopyTexture() LLUUID id = mat_data["SpecMap"].asUUID(); if (id.notNull() && !get_can_copy_texture(id)) { - mat_data["SpecMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + mat_data["SpecMap"] = DEFAULT_OBJECT_TEXTURE; mat_data["SpecMapNoCopy"] = true; } @@ -4837,7 +4850,8 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) LLToolDragAndDrop::dropTextureAllFaces(objectp, itemp_res, from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, - LLUUID::null); + LLUUID::null, + false); } else // one face { @@ -4846,6 +4860,7 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) itemp_res, from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null, + false, 0); } } @@ -5385,8 +5400,9 @@ void LLPanelFace::onPbrSelectionChanged(LLInventoryItem* itemp) bool can_modify = itemp->getPermissions().allowOperationBy(PERM_MODIFY, gAgentID); // do we have perm to transfer this material? bool is_object_owner = gAgentID == obj_owner_id; // does object for which we are going to apply material belong to the agent? bool not_for_sale = !sale_info.isForSale(); // is object for which we are going to apply material not for sale? + bool from_library = ALEXANDRIA_LINDEN_ID == itemp->getPermissions().getOwner(); - if (can_copy && can_transfer && can_modify) + if ((can_copy && can_transfer && can_modify) || from_library) { pbr_ctrl->setCanApply(true, true); return; diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 8345122f41..66d335bdc0 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -128,6 +128,7 @@ public: LLRender::eTexIndex getTextureChannelToEdit(); LLRender::eTexIndex getTextureDropChannel(); + LLGLTFMaterial::TextureInfo getPBRDropChannel(); protected: void navigateToTitleMedia(const std::string url); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 2d3b555069..5bccef3f07 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1120,9 +1120,15 @@ void LLTaskLSLBridge::openItem() LLSD floater_key; floater_key["taskid"] = mPanel->getTaskUUID(); floater_key["itemid"] = mUUID; + LLLiveLSLEditor* preview = LLFloaterReg::showTypedInstance("preview_scriptedit", floater_key, TAKE_FOCUS_YES); if (preview) { + LLSelectNode *node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(NULL, TRUE); + if (node && node->mValid) + { + preview->setObjectName(node->mName); + } preview->setObjectID(mPanel->getTaskUUID()); } } diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index e5cb903b65..0d3c76113b 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -748,7 +748,7 @@ void LLPanelOutfitEdit::onSearchEdit(const std::string& string) if (mSearchString == "") { mInventoryItemsPanel->setFilterSubString(LLStringUtil::null); - mWearableItemsList->setFilterSubString(LLStringUtil::null); + mWearableItemsList->setFilterSubString(LLStringUtil::null, true); // re-open folders that were initially open mSavedFolderState->setApply(TRUE); mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); @@ -778,8 +778,7 @@ void LLPanelOutfitEdit::onSearchEdit(const std::string& string) // set new filter string mInventoryItemsPanel->setFilterSubString(mSearchString); - mWearableItemsList->setFilterSubString(mSearchString); - + mWearableItemsList->setFilterSubString(mSearchString, true); } void LLPanelOutfitEdit::onPlusBtnClicked(void) diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index daa87485fa..e2c287b5af 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -28,19 +28,19 @@ #include "llpaneloutfitsinventory.h" -#include "llnotificationsutil.h" -#include "lltabcontainer.h" - +#include "llagentwearables.h" +#include "llappearancemgr.h" #include "llfloatersidepanelcontainer.h" #include "llinventoryfunctions.h" #include "llinventorymodelbackgroundfetch.h" -#include "llagentwearables.h" -#include "llappearancemgr.h" -#include "lloutfitobserver.h" +#include "llnotificationsutil.h" #include "lloutfitgallery.h" +#include "lloutfitobserver.h" #include "lloutfitslist.h" +#include "llpanelappearancetab.h" #include "llpanelwearing.h" #include "llsidepanelappearance.h" +#include "lltabcontainer.h" #include "llviewercontrol.h" #include "llviewerfoldertype.h" @@ -176,25 +176,12 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string) { if (!mActivePanel) return; - mFilterSubString = string; - - if (string == "") - { - mActivePanel->setFilterSubString(LLStringUtil::null); - } - if (!LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted()) { llassert(false); // this should have been done on startup LLInventoryModelBackgroundFetch::instance().start(); } - if (mActivePanel->getFilterSubString().empty() && string.empty()) - { - // current filter and new filter empty, do nothing - return; - } - // set new filter string mActivePanel->setFilterSubString(string); } @@ -342,6 +329,7 @@ bool LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata) { return mActivePanel && mActivePanel->isActionEnabled(userdata); } + // List Commands // ////////////////////////////////////////////////////////////////////////////////// @@ -370,7 +358,7 @@ void LLPanelOutfitsInventory::onTabChange() mActivePanel = dynamic_cast(mAppearanceTabs->getCurrentPanel()); if (!mActivePanel) return; - mActivePanel->setFilterSubString(mFilterSubString); + mActivePanel->checkFilterSubString(); mActivePanel->onOpen(LLSD()); updateVerbs(); @@ -397,8 +385,6 @@ bool LLPanelOutfitsInventory::isOutfitsGalleryPanelActive() const return mActivePanel->getName() == OUTFIT_GALLERY_TAB_NAME; } - - void LLPanelOutfitsInventory::setWearablesLoading(bool val) { updateVerbs(); diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index 349cc5ea81..457f52bae8 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -76,7 +76,6 @@ protected: private: LLTabContainer* mAppearanceTabs; - std::string mFilterSubString; // FIRE-17626: Attachment count in appearance floater LLInventoryCategoriesObserver* mCategoriesObserver; diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index f577f41561..d18224b223 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -2515,7 +2515,8 @@ void LLPanelProfileSecondLife::onShowTexturePicker() PERM_NONE, PERM_NONE, FALSE, - NULL); + NULL, + PICK_TEXTURE); mFloaterTexturePickerHandle = texture_floaterp->getHandle(); @@ -2917,7 +2918,8 @@ void LLPanelProfileFirstLife::onChangePhoto() PERM_NONE, PERM_NONE, FALSE, - NULL); + NULL, + PICK_TEXTURE); mFloaterTexturePickerHandle = texture_floaterp->getHandle(); diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index 8bb7c06f91..2373f26be2 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -597,9 +597,7 @@ void LLPanelProfilePick::setAvatarId(const LLUUID& avatar_id) mPickName->setEnabled(TRUE); mPickDescription->setEnabled(TRUE); // Make sure the "Set Location" button is only visible when viewing own picks - // mSetCurrentLocationButton->setVisible(TRUE); childSetVisible("set_to_curr_location_btn_lp", true); - // } else { @@ -616,7 +614,7 @@ BOOL LLPanelProfilePick::postBuild() mSaveButton = getChild("save_changes_btn"); mCreateButton = getChild("create_changes_btn"); mCancelButton = getChild("cancel_changes_btn"); - mSetCurrentLocationButton = getChild("set_to_curr_location_btn"); + mSetCurrentLocationButton = getChild("set_to_curr_location_btn"); // Keep set location button mSnapshotCtrl = getChild("pick_snapshot"); mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelProfilePick::onSnapshotChanged, this)); @@ -627,7 +625,7 @@ BOOL LLPanelProfilePick::postBuild() mSaveButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this)); mCreateButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this)); mCancelButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickCancel, this)); - mSetCurrentLocationButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSetLocation, this)); + mSetCurrentLocationButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSetLocation, this)); // Keep set location button mPickName->setKeystrokeCallback(boost::bind(&LLPanelProfilePick::onPickChanged, this, _1), NULL); mPickName->setEnabled(FALSE); @@ -789,6 +787,7 @@ BOOL LLPanelProfilePick::isDirty() const return FALSE; } +// Keep set location button void LLPanelProfilePick::onClickSetLocation() { // Save location for later use. @@ -814,6 +813,7 @@ void LLPanelProfilePick::onClickSetLocation() mLocationChanged = true; enableSaveButton(TRUE); } +// void LLPanelProfilePick::onClickSave() { diff --git a/indra/newview/llpanelprofilepicks.h b/indra/newview/llpanelprofilepicks.h index 34407d37d5..9bf6431a8b 100644 --- a/indra/newview/llpanelprofilepicks.h +++ b/indra/newview/llpanelprofilepicks.h @@ -208,10 +208,12 @@ protected: */ void resetDirty() override; + // Keep set location button /** * Callback for "Set Location" button click */ void onClickSetLocation(); + // /** * Callback for "Save" and "Create" button click @@ -235,7 +237,7 @@ protected: LLTextureCtrl* mSnapshotCtrl; LLLineEditor* mPickName; LLTextEditor* mPickDescription; - LLButton* mSetCurrentLocationButton; + LLButton* mSetCurrentLocationButton; // Keep set location button LLButton* mSaveButton; LLButton* mCreateButton; LLButton* mCancelButton; diff --git a/indra/newview/llpanelvoicedevicesettings.cpp b/indra/newview/llpanelvoicedevicesettings.cpp index 1ecf670179..0f87bf197d 100644 --- a/indra/newview/llpanelvoicedevicesettings.cpp +++ b/indra/newview/llpanelvoicedevicesettings.cpp @@ -32,6 +32,7 @@ // Viewer includes #include "llcombobox.h" #include "llsliderctrl.h" +#include "llstartup.h" #include "llviewercontrol.h" #include "llvoiceclient.h" #include "llvoicechannel.h" @@ -70,11 +71,14 @@ BOOL LLPanelVoiceDeviceSettings::postBuild() mCtrlInputDevices = getChild("voice_input_device"); mCtrlOutputDevices = getChild("voice_output_device"); + mUnmuteBtn = getChild("unmute_btn"); mCtrlInputDevices->setCommitCallback( boost::bind(&LLPanelVoiceDeviceSettings::onCommitInputDevice, this)); mCtrlOutputDevices->setCommitCallback( boost::bind(&LLPanelVoiceDeviceSettings::onCommitOutputDevice, this)); + mUnmuteBtn->setCommitCallback( + boost::bind(&LLPanelVoiceDeviceSettings::onCommitUnmute, this)); mLocalizedDeviceNames[DEFAULT_DEVICE] = getString("default_text"); mLocalizedDeviceNames["No Device"] = getString("name_no_device"); @@ -108,11 +112,27 @@ void LLPanelVoiceDeviceSettings::draw() // let user know that volume indicator is not yet available bool is_in_tuning_mode = LLVoiceClient::getInstance()->inTuningMode(); - getChildView("wait_text")->setVisible( !is_in_tuning_mode && mUseTuningMode); + bool voice_enabled = LLVoiceClient::getInstance()->voiceEnabled(); + if (voice_enabled) + { + getChildView("wait_text")->setVisible( !is_in_tuning_mode && mUseTuningMode); + getChildView("disabled_text")->setVisible(FALSE); + mUnmuteBtn->setVisible(FALSE); + } + else + { + getChildView("wait_text")->setVisible(FALSE); + + static LLCachedControl chat_enabled(gSavedSettings, "EnableVoiceChat"); + // If voice isn't enabled, it is either disabled or muted + bool voice_disabled = chat_enabled() || LLStartUp::getStartupState() <= STATE_LOGIN_WAIT; + getChildView("disabled_text")->setVisible(voice_disabled); + mUnmuteBtn->setVisible(!voice_disabled); + } LLPanel::draw(); - if (is_in_tuning_mode) + if (is_in_tuning_mode && voice_enabled) { const S32 num_bars = 5; F32 voice_power = LLVoiceClient::getInstance()->tuningGetEnergy() / LLVoiceClient::OVERDRIVEN_POWER_LEVEL; @@ -348,3 +368,8 @@ void LLPanelVoiceDeviceSettings::onInputDevicesClicked() { LLVoiceClient::getInstance()->refreshDeviceLists(false); // fill in the pop up menus again if needed. } + +void LLPanelVoiceDeviceSettings::onCommitUnmute() +{ + gSavedSettings.setBOOL("EnableVoiceChat", TRUE); +} diff --git a/indra/newview/llpanelvoicedevicesettings.h b/indra/newview/llpanelvoicedevicesettings.h index 355bc02b05..e704394d4a 100644 --- a/indra/newview/llpanelvoicedevicesettings.h +++ b/indra/newview/llpanelvoicedevicesettings.h @@ -55,12 +55,14 @@ protected: void onCommitOutputDevice(); void onOutputDevicesClicked(); void onInputDevicesClicked(); + void onCommitUnmute(); F32 mMicVolume; std::string mInputDevice; std::string mOutputDevice; class LLComboBox *mCtrlInputDevices; class LLComboBox *mCtrlOutputDevices; + class LLButton *mUnmuteBtn; BOOL mDevicesUpdated; bool mUseTuningMode; std::map mLocalizedDeviceNames; diff --git a/indra/newview/llpanelvolumepulldown.cpp b/indra/newview/llpanelvolumepulldown.cpp index 51e74a5a20..26a4d54ee2 100644 --- a/indra/newview/llpanelvolumepulldown.cpp +++ b/indra/newview/llpanelvolumepulldown.cpp @@ -54,7 +54,7 @@ LLPanelVolumePulldown::LLPanelVolumePulldown() /*// Handled centrally now mCommitCallbackRegistrar.add("Vol.setControlFalse", boost::bind(&LLPanelVolumePulldown::setControlFalse, this, _2)); mCommitCallbackRegistrar.add("Vol.SetSounds", boost::bind(&LLPanelVolumePulldown::onClickSetSounds, this)); - mCommitCallbackRegistrar.add("Vol.updateMediaAutoPlayCheckbox", boost::bind(&LLPanelVolumePulldown::updateMediaAutoPlayCheckbox, this, _1)); + mCommitCallbackRegistrar.add("Vol.updateCheckbox", boost::bind(&LLPanelVolumePulldown::updateCheckbox, this, _1, _2)); mCommitCallbackRegistrar.add("Vol.GoAudioPrefs", boost::bind(&LLPanelVolumePulldown::onAdvancedButtonClick, this, _2)); */ @@ -107,19 +107,23 @@ void LLPanelVolumePulldown::setControlFalse(const LLSD& user_data) control->set(LLSD(FALSE)); } -void LLPanelVolumePulldown::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl) +void LLPanelVolumePulldown::updateCheckbox(LLUICtrl* ctrl, const LLSD& user_data) { - std::string name = ctrl->getName(); + std::string control_name = user_data.asString(); + if (control_name == "MediaAutoPlay") + { + std::string name = ctrl->getName(); - // Disable "Allow Media to auto play" only when both - // "Streaming Music" and "Media" are unchecked. STORM-513. - if ((name == "enable_music") || (name == "enable_media")) - { - bool music_enabled = getChild("enable_music")->get(); - bool media_enabled = getChild("enable_media")->get(); + // Disable "Allow Media to auto play" only when both + // "Streaming Music" and "Media" are unchecked. STORM-513. + if ((name == "enable_music") || (name == "enable_media")) + { + bool music_enabled = getChild("enable_music")->get(); + bool media_enabled = getChild("enable_media")->get(); - getChild("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); - } + getChild("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); + } + } } void LLPanelVolumePulldown::onClickSetSounds() diff --git a/indra/newview/llpanelvolumepulldown.h b/indra/newview/llpanelvolumepulldown.h index 90e826e76b..16d7fecc20 100644 --- a/indra/newview/llpanelvolumepulldown.h +++ b/indra/newview/llpanelvolumepulldown.h @@ -44,7 +44,7 @@ class LLPanelVolumePulldown : public LLPanelPulldown void onClickSetSounds(); // Disables "Allow Media to auto play" check box only when both // "Streaming Music" and "Media" are unchecked. Otherwise enables it. - void updateMediaAutoPlayCheckbox(LLUICtrl* ctrl); + void updateCheckbox(LLUICtrl* ctrl, const LLSD& user_data); void onAdvancedButtonClick(const LLSD& user_data); */ diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index 04baa9b0f1..84e59c4017 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -243,8 +243,6 @@ protected: ////////////////////////////////////////////////////////////////////////// -std::string LLPanelAppearanceTab::sFilterSubString = LLStringUtil::null; - static LLPanelInjector t_panel_wearing("panel_wearing"); LLPanelWearing::LLPanelWearing() @@ -368,10 +366,11 @@ void LLPanelWearing::startUpdateTimer() } // virtual -void LLPanelWearing::setFilterSubString(const std::string& string) +void LLPanelWearing::onFilterSubStringChanged(const std::string& new_string, const std::string& old_string) { - sFilterSubString = string; - mCOFItemsList->setFilterSubString(sFilterSubString); + mCOFItemsList->setFilterSubString(new_string, true); + + mAccordionCtrl->arrange(); } // virtual diff --git a/indra/newview/llpanelwearing.h b/indra/newview/llpanelwearing.h index d1d5d04fd5..d3d23e4866 100644 --- a/indra/newview/llpanelwearing.h +++ b/indra/newview/llpanelwearing.h @@ -62,7 +62,7 @@ public: /*virtual*/ void onOpen(const LLSD& info); - /*virtual*/ void setFilterSubString(const std::string& string); + /*virtual*/ void onFilterSubStringChanged(const std::string& new_string, const std::string& old_string); /*virtual*/ bool isActionEnabled(const LLSD& userdata); diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index d2c82b05e0..6e3bf21510 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -88,6 +88,9 @@ #include "llexperiencecache.h" #include "llfloaterexperienceprofile.h" #include "llviewerassetupload.h" +//#include "lltoggleablemenu.h" // FIRE-20818: User-selectable font and size for script editor +//#include "llmenubutton.h" // FIRE-20818: User-selectable font and size for script editor +#include "llinventoryfunctions.h" #include "llloadingindicator.h" // Compile indicator #include "lliconctrl.h" // Compile indicator // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) @@ -365,6 +368,38 @@ void LLFloaterScriptSearch::onSearchBoxCommit() #endif // +/// --------------------------------------------------------------------------- + +class LLScriptMovedObserver : public LLInventoryObserver +{ + public: + LLScriptMovedObserver(LLPreviewLSL *floater) : mPreview(floater) { gInventory.addObserver(this); } + virtual ~LLScriptMovedObserver() { gInventory.removeObserver(this); } + virtual void changed(U32 mask); + + private: + LLPreviewLSL *mPreview; +}; + +void LLScriptMovedObserver::changed(U32 mask) +{ + const std::set &mChangedItemIDs = gInventory.getChangedIDs(); + std::set::const_iterator it; + + const LLUUID &item_id = mPreview->getScriptID(); + + for (it = mChangedItemIDs.begin(); it != mChangedItemIDs.end(); it++) + { + if (*it == item_id) + { + if ((mask & (LLInventoryObserver::STRUCTURE)) != 0) + { + mPreview->setDirty(); + } + } + } +} + /// --------------------------------------------------------------------------- /// LLScriptEdCore /// --------------------------------------------------------------------------- @@ -588,6 +623,15 @@ BOOL LLScriptEdCore::postBuild() LLSyntaxIdLSL::getInstance()->initialize(); processKeywords(); + // FIRE-20818: User-selectable font and size for script editor + //mCommitCallbackRegistrar.add("FontSize.Set", boost::bind(&LLScriptEdCore::onChangeFontSize, this, _2)); + //mEnableCallbackRegistrar.add("FontSize.Check", boost::bind(&LLScriptEdCore::isFontSizeChecked, this, _2)); + + //LLToggleableMenu *context_menu = LLUICtrlFactory::getInstance()->createFromFile( + // "menu_lsl_font_size.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + //getChild("font_btn")->setMenu(context_menu, LLMenuButton::MP_BOTTOM_LEFT, true); + // + return TRUE; } @@ -1267,7 +1311,7 @@ void LLScriptEdCore::setHelpPage(const std::string& help_string) LLUIString url_string = gSavedSettings.getString("LSLHelpURL"); - url_string.setArg("[LSL_STRING]", help_string); + url_string.setArg("[LSL_STRING]", help_string.empty() ? HELP_LSL_PORTAL_TOPIC : help_string); addHelpItemToHistory(help_string); @@ -1835,6 +1879,20 @@ LLUUID LLScriptEdCore::getAssociatedExperience()const } // FIRE-20818: User-selectable font and size for script editor +//void LLScriptEdCore::onChangeFontSize(const LLSD &userdata) +//{ +// const std::string font_name = userdata.asString(); +// gSavedSettings.setString("LSLFontSizeName", font_name); +//} +// +//bool LLScriptEdCore::isFontSizeChecked(const LLSD &userdata) +//{ +// const std::string current_size_name = LLScriptEditor::getScriptFontSize(); +// const std::string size_name = userdata.asString(); +// +// return (size_name == current_size_name); +//} + void LLScriptEdCore::onFontChanged() { LLFontGL* font = LLFontGL::getFont(LLFontDescriptor(gSavedSettings.getString("FSScriptingFontName"), gSavedSettings.getString("FSScriptingFontSize"), LLFontGL::NORMAL)); @@ -2112,6 +2170,21 @@ bool LLScriptEdContainer::onExternalChange(const std::string& filename) return true; } +BOOL LLScriptEdContainer::handleKeyHere(KEY key, MASK mask) +{ + if (('A' == key) && (MASK_CONTROL == (mask & MASK_MODIFIERS))) + { + mScriptEd->selectAll(); + return TRUE; + } + + if (!LLPreview::handleKeyHere(key, mask)) + { + return mScriptEd->handleKeyHere(key, mask); + } + return TRUE; +} + // FIRE-16740: Color syntax highlighting changes don't immediately appear in script window void LLScriptEdContainer::updateStyle() { @@ -2164,6 +2237,14 @@ LLPreviewLSL::LLPreviewLSL(const LLSD& key ) mPendingUploads(0) { mFactoryMap["script panel"] = LLCallbackMap(LLPreviewLSL::createScriptEdPanel, this); + + mItemObserver = new LLScriptMovedObserver(this); +} + +LLPreviewLSL::~LLPreviewLSL() +{ + delete mItemObserver; + mItemObserver = NULL; } // virtual @@ -2175,10 +2256,25 @@ BOOL LLPreviewLSL::postBuild() if (item) { getChild("desc")->setValue(item->getDescription()); + + std::string item_path = get_category_path(item->getParentUUID()); + // Make ugly location display better + //getChild("path_txt")->setValue(item_path); + //getChild("path_txt")->setToolTip(item_path); + getChild("path_txt")->setTextArg("[PATH]", LLStringExplicit(item_path)); + getChild("path_txt")->setToolTipArg(LLStringExplicit("[PATH]"), LLStringExplicit(item_path)); + // } + // Make ugly location display better + else + { + getChild("path_txt")->setTextArg("[PATH]", LLStringExplicit("-")); + getChild("path_txt")->setToolTipArg(LLStringExplicit("[PATH]"), LLStringExplicit("-")); + } + // childSetCommitCallback("desc", LLPreview::onText, this); getChild("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe); - + return LLPreview::postBuild(); } @@ -2189,8 +2285,21 @@ void LLPreviewLSL::draw() { setTitle(LLTrans::getString("ScriptWasDeleted")); mScriptEd->setItemRemoved(TRUE); + // Make ugly location display better + getChild("path_txt")->setTextArg("[PATH]", LLStringExplicit("-")); + getChild("path_txt")->setToolTipArg(LLStringExplicit("[PATH]"), LLStringExplicit("-")); + // } - + else if (mDirty) + { + std::string item_path = get_category_path(item->getParentUUID()); + // Make ugly location display better + //getChild("path_txt")->setValue(item_path); + //getChild("path_txt")->setToolTip(item_path); + getChild("path_txt")->setTextArg("[PATH]", LLStringExplicit(item_path)); + getChild("path_txt")->setToolTipArg(LLStringExplicit("[PATH]"), LLStringExplicit(item_path)); + // + } LLPreview::draw(); } // virtual @@ -2608,7 +2717,8 @@ LLLiveLSLEditor::LLLiveLSLEditor(const LLSD& key) : mPendingUploads(0), mIsModifiable(FALSE), mIsNew(false), - mIsSaving(FALSE) + mIsSaving(FALSE), + mObjectName("") { mFactoryMap["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this); } @@ -2773,6 +2883,10 @@ void LLLiveLSLEditor::loadAsset() } refreshFromItem(); + // Make ugly location display better + //getChild("obj_name")->setValue(mObjectName); + getChild("obj_name")->setTextArg("[SOURCE_OBJECT]", LLStringExplicit(mObjectName) ); + // // This is commented out, because we don't completely // handle script exports yet. /* diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 661cc386ae..d34dd9ced7 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -36,6 +36,7 @@ #include "llfloatergotoline.h" #include "lllivefile.h" #include "llsyntaxid.h" +#include "llscripteditor.h" #include class LLLiveLSLFile; @@ -53,6 +54,7 @@ class LLViewerInventoryItem; class LLScriptEdContainer; class LLFloaterGotoLine; class LLFloaterExperienceProfile; +class LLScriptMovedObserver; // [SL:KB] - Patch: Build-ScriptRecover | Checked: 2011-11-23 (Catznip-3.2.0) class LLEventTimer; // [/SL:KB] @@ -167,7 +169,15 @@ public: void setAssetID( const LLUUID& asset_id){ mAssetID = asset_id; }; LLUUID getAssetID() { return mAssetID; } -private: + // FIRE-20818: User-selectable font and size for script editor + //bool isFontSizeChecked(const LLSD &userdata); + //void onChangeFontSize(const LLSD &size_name); + // + + virtual BOOL handleKeyHere(KEY key, MASK mask); + void selectAll() { mEditor->selectAll(); } + + private: // NaCl - LSL Preprocessor void onToggleProc(); boost::signals2::connection mTogglePreprocConnection; @@ -186,8 +196,6 @@ private: // Show keyword help on F1 void selectFirstError(); - virtual BOOL handleKeyHere(KEY key, MASK mask); - void enableSave(BOOL b) {mEnableSave = b;} // Advanced Script Editor @@ -287,6 +295,8 @@ public: // FIRE-16740: Color syntax highlighting changes don't immediately appear in script window void updateStyle(); + BOOL handleKeyHere(KEY key, MASK mask); + protected: std::string getTmpFileName(const std::string& script_name); // [SL:KB] - Patch: Build-ScriptRecover | Checked: 2011-11-23 (Catznip-3.2.0) | Added: Catznip-3.2.0 @@ -309,6 +319,12 @@ class LLPreviewLSL : public LLScriptEdContainer { public: LLPreviewLSL(const LLSD& key ); + ~LLPreviewLSL(); + + LLUUID getScriptID() { return mItemUUID; } + + void setDirty() { mDirty = true; } + virtual void callbackLSLCompileSucceeded(); virtual void callbackLSLCompileFailed(const LLSD& compile_errors); @@ -347,6 +363,8 @@ protected: // Can safely close only after both text and bytecode are uploaded S32 mPendingUploads; + LLScriptMovedObserver* mItemObserver; + }; @@ -383,6 +401,8 @@ public: void requestExperiences(); void experienceChanged(); void addAssociatedExperience(const LLSD& experience); + + void setObjectName(std::string name) { mObjectName = name; } private: virtual BOOL canClose(); @@ -444,6 +464,7 @@ private: LLSD mExperienceIds; LLHandle mExperienceProfile; + std::string mObjectName; }; #endif // LL_LLPREVIEWSCRIPT_H diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp index 7fd89ff4f8..7b1401c49a 100644 --- a/indra/newview/llscenemonitor.cpp +++ b/indra/newview/llscenemonitor.cpp @@ -657,19 +657,6 @@ void LLSceneMonitor::dumpToFile(const std::string &file_name) } } - typedef LLTrace::StatType trace_mem; - for (auto& it : trace_mem::instance_snapshot()) - { - os << it.getName() << "(KiB)"; - - for (S32 frame = 1; frame <= frame_count; frame++) - { - os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(it).valueInUnits(); - } - - os << '\n'; - } - os.flush(); os.close(); } diff --git a/indra/newview/llscripteditor.cpp b/indra/newview/llscripteditor.cpp index c12f29f82a..7870cf8c9f 100644 --- a/indra/newview/llscripteditor.cpp +++ b/indra/newview/llscripteditor.cpp @@ -30,6 +30,7 @@ #include "llsyntaxid.h" #include "lllocalcliprect.h" +#include "llviewercontrol.h" #include "llpreviewscript.h" @@ -40,13 +41,15 @@ const S32 UI_TEXTEDITOR_LINE_NUMBER_MARGIN = 40; static LLDefaultChildRegistry::Register r("script_editor"); LLScriptEditor::Params::Params() -: show_line_numbers("show_line_numbers", true) +: show_line_numbers("show_line_numbers", true), + default_font_size("default_font_size", false) {} LLScriptEditor::LLScriptEditor(const Params& p) : LLTextEditor(p) -, mShowLineNumbers(p.show_line_numbers) +, mShowLineNumbers(p.show_line_numbers), + mUseDefaultFontSize(p.default_font_size) { if (mShowLineNumbers) { @@ -55,6 +58,13 @@ LLScriptEditor::LLScriptEditor(const Params& p) } } +BOOL LLScriptEditor::postBuild() +{ + // FIRE-20818: User-selectable font and size for script editor + //gSavedSettings.getControl("LSLFontSizeName")->getCommitSignal()->connect(boost::bind(&LLScriptEditor::onFontSizeChange, this)); + return LLTextEditor::postBuild(); +} + void LLScriptEditor::draw() { { @@ -117,15 +127,11 @@ void LLScriptEditor::drawLineNumbers() // draw the line numbers if(line.mLineNum != last_line_num && line.mRect.mTop <= scrolled_view_rect.mTop) { - // Script editor ignoring font selection - //const LLFontGL *num_font = LLFontGL::getFontMonospace(); - const LLFontGL *num_font = getFont(); - // const LLWString ltext = utf8str_to_wstring(llformat("%d", line.mLineNum )); BOOL is_cur_line = cursor_line == line.mLineNum; const U8 style = is_cur_line ? LLFontGL::BOLD : LLFontGL::NORMAL; const LLColor4 fg_color = is_cur_line ? mCursorColor : mReadOnlyFgColor; - num_font->render( + getFont()->render( ltext, // string to draw 0, // begin offset UI_TEXTEDITOR_LINE_NUMBER_MARGIN - 2, // x @@ -153,8 +159,12 @@ void LLScriptEditor::loadKeywords() LL_PROFILE_ZONE_SCOPED; mKeywords.processTokens(); + // FIRE-20818: User-selectable font and size for script editor + //LLStyleConstSP style = new LLStyle(LLStyle::Params().font(getScriptFont()).color(mDefaultColor.get())); + LLStyleConstSP style = new LLStyle(LLStyle::Params().font(getFont()).color(mDefaultColor.get())); + segment_vec_t segment_list; - mKeywords.findSegments(&segment_list, getWText(), mDefaultColor.get(), *this); + mKeywords.findSegments(&segment_list, getWText(), *this, style); mSegments.clear(); segment_set_t::iterator insert_it = mSegments.begin(); @@ -180,7 +190,8 @@ void LLScriptEditor::loadKeywords(const std::string& filename, mKeywords.addToken(LLKeywordToken::TT_WORD, name, color, tooltips[i] ); } segment_vec_t segment_list; - mKeywords.findSegments(&segment_list, getWText(), mDefaultColor.get(), *this); + LLStyleConstSP style = new LLStyle(LLStyle::Params().font(getFont()).color(mDefaultColor.get())); + mKeywords.findSegments(&segment_list, getWText(), *this, style); mSegments.clear(); segment_set_t::iterator insert_it = mSegments.begin(); @@ -197,9 +208,14 @@ void LLScriptEditor::updateSegments() if (mReflowIndex < S32_MAX && mKeywords.isLoaded() && mParseOnTheFly) { LL_PROFILE_ZONE_SCOPED; + + // FIRE-20818: User-selectable font and size for script editor + //LLStyleConstSP style = new LLStyle(LLStyle::Params().font(getScriptFont()).color(mDefaultColor.get())); + LLStyleConstSP style = new LLStyle(LLStyle::Params().font(getFont()).color(mDefaultColor.get())); + // HACK: No non-ascii keywords for now segment_vec_t segment_list; - mKeywords.findSegments(&segment_list, getWText(), mDefaultColor.get(), *this); + mKeywords.findSegments(&segment_list, getWText(), *this, style); clearSegments(); for (segment_vec_t::iterator list_it = segment_list.begin(); list_it != segment_list.end(); ++list_it) @@ -250,6 +266,28 @@ void LLScriptEditor::drawSelectionBackground() } } +// FIRE-20818: User-selectable font and size for script editor +//std::string LLScriptEditor::getScriptFontSize() +//{ +// static LLCachedControl size_name(gSavedSettings, "LSLFontSizeName", "Monospace"); +// return size_name; +//} +// +//LLFontGL* LLScriptEditor::getScriptFont() +//{ +// std::string font_size_name = mUseDefaultFontSize ? "Monospace" : getScriptFontSize(); +// return LLFontGL::getFont(LLFontDescriptor("Monospace", font_size_name, 0)); +//} +// +//void LLScriptEditor::onFontSizeChange() +//{ +// if (!mUseDefaultFontSize) +// { +// needsReflow(); +// } +//} +// + // Improved Home-key behavior //virtual void LLScriptEditor::startOfLine() diff --git a/indra/newview/llscripteditor.h b/indra/newview/llscripteditor.h index 088d9e7f10..438989fee1 100644 --- a/indra/newview/llscripteditor.h +++ b/indra/newview/llscripteditor.h @@ -37,7 +37,7 @@ public: struct Params : public LLInitParam::Block { Optional show_line_numbers; - + Optional default_font_size; Params(); }; @@ -45,6 +45,7 @@ public: // LLView override virtual void draw(); + BOOL postBuild(); // Improved Home-key behavior // LLTextBase override @@ -56,7 +57,13 @@ public: LLKeywords::keyword_iterator_t keywordsBegin() { return mKeywords.begin(); } LLKeywords::keyword_iterator_t keywordsEnd() { return mKeywords.end(); } - // Re-add legacy format support + // FIRE-20818: User-selectable font and size for script editor + //static std::string getScriptFontSize(); + //LLFontGL* getScriptFont(); + //void onFontSizeChange(); + // + + // Re-add legacy format support void loadKeywords(const std::string& filename, const std::vector& funcs, const std::vector& tooltips, @@ -80,6 +87,7 @@ private: LLKeywords mKeywords; bool mShowLineNumbers; + bool mUseDefaultFontSize; }; #endif // LL_SCRIPTEDITOR_H diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp index 87c1330f8d..8087614d34 100644 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -259,21 +259,17 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint ) // Make sure we're not taking the slider out of bounds // (this is where some simple UI limits are stored) - F32 new_percent = weightToPercent(new_weight); - LLSliderCtrl* slider = getChild("param slider"); - if (slider) + F32 new_percent = weightToSlider(new_weight); + if (mSlider->getMinValue() < new_percent + && new_percent < mSlider->getMaxValue()) { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) - { - // [Legacy Bake] - //mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight); - mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE); - mWearable->writeToAvatar(gAgentAvatarp); - gAgentAvatarp->updateVisualParams(); + // [Legacy Bake] + //mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight); + mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE); + mWearable->writeToAvatar(gAgentAvatarp); + gAgentAvatarp->updateVisualParams(); - slider->setValue( weightToPercent( new_weight ) ); - } + mSlider->setValue( weightToSlider( new_weight ) ); } } } @@ -294,19 +290,15 @@ void LLScrollingPanelParam::onHintMinMouseUp( void* userdata ) F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight(); // step a fraction in the negative directiona F32 new_weight = current_weight - (range / 10.f); - F32 new_percent = self->weightToPercent(new_weight); - LLSliderCtrl* slider = self->getChild("param slider"); - if (slider) + F32 new_percent = self->weightToSlider(new_weight); + if (self->mSlider->getMinValue() < new_percent + && new_percent < self->mSlider->getMaxValue()) { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) - { - // [Legacy Bake] - //self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); - self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); - self->mWearable->writeToAvatar(gAgentAvatarp); - slider->setValue( self->weightToPercent( new_weight ) ); - } + // [Legacy Bake] + //self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); + self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); + self->mWearable->writeToAvatar(gAgentAvatarp); + self->mSlider->setValue( self->weightToSlider( new_weight ) ); } } @@ -330,35 +322,18 @@ void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata ) F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight(); // step a fraction in the negative direction F32 new_weight = current_weight + (range / 10.f); - F32 new_percent = self->weightToPercent(new_weight); - LLSliderCtrl* slider = self->getChild("param slider"); - if (slider) + F32 new_percent = self->weightToSlider(new_weight); + if (self->mSlider->getMinValue() < new_percent + && new_percent < self->mSlider->getMaxValue()) { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) - { - // [Legacy Bake] - //self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); - self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); - self->mWearable->writeToAvatar(gAgentAvatarp); - slider->setValue( self->weightToPercent( new_weight ) ); - } + // [Legacy Bake] + //self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); + self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); + self->mWearable->writeToAvatar(gAgentAvatarp); + self->mSlider->setValue( self->weightToSlider( new_weight ) ); } } } LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax ); } - - -F32 LLScrollingPanelParam::weightToPercent( F32 weight ) -{ - LLViewerVisualParam* param = mParam; - return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; -} - -F32 LLScrollingPanelParam::percentToWeight( F32 percent ) -{ - LLViewerVisualParam* param = mParam; - return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); -} diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h index c7a47d5c7a..dc344486fc 100644 --- a/indra/newview/llscrollingpanelparam.h +++ b/indra/newview/llscrollingpanelparam.h @@ -61,9 +61,6 @@ public: void onHintMouseDown( LLVisualParamHint* hint ); void onHintHeldDown( LLVisualParamHint* hint ); - F32 weightToPercent( F32 weight ); - F32 percentToWeight( F32 percent ); - public: // Constants for LLPanelVisualParam const static F32 PARAM_STEP_TIME_THRESHOLD; diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp index 97ef946b56..3c066cb590 100644 --- a/indra/newview/llscrollingpanelparambase.cpp +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -43,6 +43,7 @@ LLScrollingPanelParamBase::LLScrollingPanelParamBase( const LLPanel::Params& pan LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, LLJoint* jointp, BOOL use_hints) : LLScrollingPanel( panel_params ), mParam(param), + mSlider(nullptr), mAllowModify(allow_modify), mWearable(wearable) { @@ -50,13 +51,15 @@ LLScrollingPanelParamBase::LLScrollingPanelParamBase( const LLPanel::Params& pan buildFromFile( "panel_scrolling_param.xml"); else buildFromFile( "panel_scrolling_param_base.xml"); - - getChild("param slider")->setValue(weightToPercent(param->getWeight())); + + mSlider = getChild("param slider"); + mSlider->setMaxValue(100.f * (mParam->getMaxWeight() - mParam->getMinWeight())); + mSlider->setValue(weightToSlider(param->getWeight())); std::string display_name = LLTrans::getString(param->getDisplayName()); - getChild("param slider")->setLabelArg("[DESC]", display_name); - getChildView("param slider")->setEnabled(mAllowModify); - childSetCommitCallback("param slider", LLScrollingPanelParamBase::onSliderMoved, this); + mSlider->setLabelArg("[DESC]", display_name); + mSlider->setEnabled(mAllowModify); + mSlider->setCommitCallback(boost::bind(LLScrollingPanelParamBase::onSliderMoved, mSlider, this)); setVisible(FALSE); setBorderVisible( FALSE ); @@ -77,9 +80,9 @@ void LLScrollingPanelParamBase::updatePanel(BOOL allow_modify) } F32 current_weight = mWearable->getVisualParamWeight( param->getID() ); - getChild("param slider")->setValue(weightToPercent( current_weight ) ); + mSlider->setValue(weightToSlider( current_weight ) ); mAllowModify = allow_modify; - getChildView("param slider")->setEnabled(mAllowModify); + mSlider->setEnabled(mAllowModify); } // static @@ -90,7 +93,7 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata) LLViewerVisualParam* param = self->mParam; F32 current_weight = self->mWearable->getVisualParamWeight( param->getID() ); - F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() ); + F32 new_weight = self->sliderToWeight( (F32)slider->getValue().asReal() ); if (current_weight != new_weight ) { // [Legacy Bake] @@ -101,14 +104,12 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata) } } -F32 LLScrollingPanelParamBase::weightToPercent( F32 weight ) +F32 LLScrollingPanelParamBase::weightToSlider(F32 weight) { - LLViewerVisualParam* param = mParam; - return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; + return (weight - mParam->getMinWeight()) * 100.f; } -F32 LLScrollingPanelParamBase::percentToWeight( F32 percent ) +F32 LLScrollingPanelParamBase::sliderToWeight(F32 slider) { - LLViewerVisualParam* param = mParam; - return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); + return slider / 100.f + mParam->getMinWeight(); } diff --git a/indra/newview/llscrollingpanelparambase.h b/indra/newview/llscrollingpanelparambase.h index 9538826251..e7f88a21bd 100644 --- a/indra/newview/llscrollingpanelparambase.h +++ b/indra/newview/llscrollingpanelparambase.h @@ -36,6 +36,7 @@ class LLViewerVisualParam; class LLWearable; class LLVisualParamHint; class LLViewerVisualParam; +class LLSliderCtrl; class LLJoint; class LLScrollingPanelParamBase : public LLScrollingPanel @@ -49,11 +50,13 @@ public: static void onSliderMoved(LLUICtrl* ctrl, void* userdata); - F32 weightToPercent( F32 weight ); - F32 percentToWeight( F32 percent ); + F32 weightToSlider(F32 weight); + F32 sliderToWeight(F32 slider); public: LLViewerVisualParam* mParam; + LLSliderCtrl* mSlider; + protected: BOOL mAllowModify; LLWearable *mWearable; diff --git a/indra/newview/llsearchhistory.cpp b/indra/newview/llsearchhistory.cpp index 449e0080f0..66e377cb8d 100644 --- a/indra/newview/llsearchhistory.cpp +++ b/indra/newview/llsearchhistory.cpp @@ -75,6 +75,17 @@ bool LLSearchHistory::save() { // build filename for each user std::string resolved_filename = getHistoryFilePath(); + + // delete the file if it is empty or contains only empty entries + if (std::find_if(mSearchHistory.begin(), mSearchHistory.end(), [](const LLSearchHistoryItem& x) + { + return !x.search_query.empty(); + }) == mSearchHistory.end()) + { + remove(resolved_filename.c_str()); + return true; + } + // open a file for writing llofstream file(resolved_filename.c_str()); if (!file.is_open()) diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 6b31866705..bc519ed7ef 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -97,7 +97,7 @@ #include "llvovolume.h" #include "pipeline.h" #include "llviewershadermgr.h" -#include "llpanelface.h" +// #include "llpanelface.h" // switchable edit texture/materials panel - include not needed // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) #include "rlvactions.h" #include "rlvhandler.h" @@ -1919,8 +1919,52 @@ bool LLObjectSelection::applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* i //----------------------------------------------------------------------------- // selectionSetImage() //----------------------------------------------------------------------------- +// Allow editing of non-PBR materials in-situ +template +struct TextureApplyFunctor : public LLSelectedTEFunctor +{ + LLViewerInventoryItem* mItem; + LLUUID mImageID; + TextureApplyFunctor(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {} + bool apply(LLViewerObject* objectp, S32 te) override + { + if(!objectp || !objectp->permModify()) + { + return false; + } + + if (mItem && objectp->isAttachment()) + { + const LLPermissions& perm = mItem->getPermissions(); + BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; + if (!unrestricted) + { + return false; + } + } + + if (mItem) + { + if constexpr (IsPBR) + { + LLToolDragAndDrop::dropTextureOneFace(objectp, te, mItem, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null, false); + } + else + { + LLToolDragAndDrop::dropTextureOneFace(objectp, te, mItem, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null, false, -2); // -2 means no PBR + } + } + else // not an inventory item + { + objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + } + + return true; + } +}; +// // *TODO: re-arch texture applying out of lltooldraganddrop -bool LLSelectMgr::selectionSetImage(const LLUUID& imageid) +bool LLSelectMgr::selectionSetImage(const LLUUID& imageid, bool isPBR) { // First for (no copy) textures and multiple object selection LLViewerInventoryItem* item = gInventory.getItem(imageid); @@ -1935,59 +1979,73 @@ bool LLSelectMgr::selectionSetImage(const LLUUID& imageid) return false; } - struct f : public LLSelectedTEFunctor - { - LLViewerInventoryItem* mItem; - LLUUID mImageID; - f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {} - bool apply(LLViewerObject* objectp, S32 te) - { - if(!objectp || !objectp->permModify()) - { - return false; - } + // Allow editing of non-PBR materials in-situ + // struct f : public LLSelectedTEFunctor + // { + // LLViewerInventoryItem* mItem; + // LLUUID mImageID; + // f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {} + // bool apply(LLViewerObject* objectp, S32 te) + // { + // if(!objectp || !objectp->permModify()) + // { + // return false; + // } - // Might be better to run willObjectAcceptInventory - if (mItem && objectp->isAttachment()) - { - const LLPermissions& perm = mItem->getPermissions(); - BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; - if (!unrestricted) - { - // Attachments are in world and in inventory simultaneously, - // at the moment server doesn't support such a situation. - return false; - } - } + // // Might be better to run willObjectAcceptInventory + // if (mItem && objectp->isAttachment()) + // { + // const LLPermissions& perm = mItem->getPermissions(); + // BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; + // if (!unrestricted) + // { + // // Attachments are in world and in inventory simultaneously, + // // at the moment server doesn't support such a situation. + // return false; + // } + // } - if (mItem) - { - LLToolDragAndDrop::dropTextureOneFace(objectp, - te, - mItem, - LLToolDragAndDrop::SOURCE_AGENT, - LLUUID::null); - } - else // not an inventory item - { - // Texture picker defaults aren't inventory items - // * Don't need to worry about permissions for them - // * Can just apply the texture and be done with it. - objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); - } - - return true; - } - }; + // if (mItem) + // { + // LLToolDragAndDrop::dropTextureOneFace(objectp, + // te, + // mItem, + // LLToolDragAndDrop::SOURCE_AGENT, + // LLUUID::null, + // false); + // } + // else // not an inventory item + // { + // // Texture picker defaults aren't inventory items + // // * Don't need to worry about permissions for them + // // * Can just apply the texture and be done with it. + // objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + // } + // return true; + // } + // }; + // if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) { getSelection()->applyNoCopyTextureToTEs(item); } else { - f setfunc(item, imageid); - getSelection()->applyToTEs(&setfunc); + // Allow editing of non-PBR materials in-situ + // f setfunc(item, imageid); + // getSelection()->applyToTEs(&setfunc); + TextureApplyFunctor setfuncPBR(item, imageid); // For PBR textures + TextureApplyFunctor setfuncBP(item, imageid); // For non-PBR textures + if(isPBR) + { + getSelection()->applyToTEs(&setfuncPBR); + } + else + { + getSelection()->applyToTEs(&setfuncBP); + } + // } @@ -2046,26 +2104,30 @@ bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id) { return false; } - if (mItem && objectp->isAttachment()) - { - const LLPermissions& perm = mItem->getPermissions(); - BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; - if (!unrestricted) - { - // Attachments are in world and in inventory simultaneously, - // at the moment server doesn't support such a situation. - return false; - } - } LLUUID asset_id = mMatId; if (mItem) { - // If success, the material may be copied into the object's inventory - BOOL success = LLToolDragAndDrop::handleDropMaterialProtections(objectp, mItem, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); - if (!success) + const LLPermissions& perm = mItem->getPermissions(); + bool from_library = perm.getOwner() == ALEXANDRIA_LINDEN_ID; + if (objectp->isAttachment()) + { + bool unrestricted = (perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED; + + if (!unrestricted && !from_library) + { + // Attachments are in world and in inventory simultaneously, + // at the moment server doesn't support such a situation. + return false; + } + } + + if (!from_library + // Check if item may be copied into the object's inventory + && !LLToolDragAndDrop::handleDropMaterialProtections(objectp, mItem, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null)) { return false; } + asset_id = mItem->getAssetUUID(); if (asset_id.isNull()) { @@ -2081,11 +2143,13 @@ bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id) }; bool success = true; - if (item && - (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) || + if (item + && (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) || !item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()) || !item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()) - )) + ) + && item->getPermissions().getOwner() != ALEXANDRIA_LINDEN_ID + ) { success = success && getSelection()->applyRestrictedPbrMaterialToTEs(item); } @@ -2251,7 +2315,9 @@ void LLSelectMgr::selectionRevertShinyColors() LLMaterialPtr old_mat = object->getTEref(te).getMaterialParams(); if (!old_mat.isNull()) { - LLMaterialPtr new_mat = gFloaterTools->getPanelFace()->createDefaultMaterial(old_mat); + // switchable edit texture/materials panel + // LLMaterialPtr new_mat = gFloaterTools->getPanelFace()->createDefaultMaterial(old_mat); + LLMaterialPtr new_mat = gFloaterTools->createDefaultMaterial(old_mat); new_mat->setSpecularLightColor(color); object->getTEref(te).setMaterialParams(new_mat); LLMaterialMgr::getInstance()->put(object->getID(), te, *new_mat); @@ -3167,7 +3233,9 @@ void LLSelectMgr::adjustTexturesByScale(BOOL send_to_sim, BOOL stretch) if (tep && !tep->getMaterialParams().isNull()) { LLMaterialPtr orig = tep->getMaterialParams(); - LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + // switchable edit texture/materials panel + // LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + LLMaterialPtr p = gFloaterTools->createDefaultMaterial(orig); p->setNormalRepeat(normal_scale_s, normal_scale_t); p->setSpecularRepeat(specular_scale_s, specular_scale_t); @@ -3193,7 +3261,9 @@ void LLSelectMgr::adjustTexturesByScale(BOOL send_to_sim, BOOL stretch) if (tep && !tep->getMaterialParams().isNull()) { LLMaterialPtr orig = tep->getMaterialParams(); - LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + // switchable edit texture/materials panel + // LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + LLMaterialPtr p = gFloaterTools->createDefaultMaterial(orig); p->setNormalRepeat(normal_scale_s, normal_scale_t); p->setSpecularRepeat(specular_scale_s, specular_scale_t); @@ -4436,9 +4506,12 @@ BOOL LLSelectMgr::selectGetAggregateTexturePermissions(LLAggregatePermissions& r BOOL LLSelectMgr::isMovableAvatarSelected() { - if (mAllowSelectAvatar) + if (mAllowSelectAvatar && getSelection()->getObjectCount() == 1) { - return (getSelection()->getObjectCount() == 1) && (getSelection()->getFirstRootObject()->isAvatar()) && getSelection()->getFirstMoveableNode(TRUE); + // nothing but avatar should be selected, so check that + // there is only one selected object and it is a root + LLViewerObject* obj = getSelection()->getFirstRootObject(); + return obj && obj->isAvatar() && getSelection()->getFirstMoveableNode(TRUE); } return FALSE; } diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 0902fc1b39..5bea652f10 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -717,7 +717,7 @@ public: void selectionSetDensity(F32 density); void selectionSetRestitution(F32 restitution); void selectionSetMaterial(U8 material); - bool selectionSetImage(const LLUUID& imageid); // could be item or asset id + bool selectionSetImage(const LLUUID& imageid, bool isPBR=true); // inject PBR awareness. bool selectionSetGLTFMaterial(const LLUUID& mat_id); // material id only void selectionSetColor(const LLColor4 &color); void selectionSetColorOnly(const LLColor4 &color); // Set only the RGB channels diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 7009fb98ab..c07c939862 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -739,7 +739,6 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force) static LLCachedControl auto_adjust_blue_horizon_scale(gSavedSettings, "RenderSkyAutoAdjustBlueHorizonScale", 1.f); static LLCachedControl auto_adjust_blue_density_scale(gSavedSettings, "RenderSkyAutoAdjustBlueDensityScale", 1.f); static LLCachedControl auto_adjust_sun_color_scale(gSavedSettings, "RenderSkyAutoAdjustSunColorScale", 1.f); - static LLCachedControl auto_adjust_probe_ambiance(gSavedSettings, "RenderSkyAutoAdjustProbeAmbiance", 1.f); static LLCachedControl sunlight_scale(gSavedSettings, "RenderSkySunlightScale", 1.5f); static LLCachedControl ambient_scale(gSavedSettings, "RenderSkyAmbientScale", 1.5f); @@ -772,8 +771,7 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force) shader->uniform3fv(LLShaderMgr::BLUE_DENSITY, blue_density.mV); shader->uniform3fv(LLShaderMgr::BLUE_HORIZON, blue_horizon.mV); - LLSettingsSky::sAutoAdjustProbeAmbiance = auto_adjust_probe_ambiance; - probe_ambiance = auto_adjust_probe_ambiance; // NOTE -- must match LLSettingsSky::getReflectionProbeAmbiance value for "auto_adjust" true + probe_ambiance = sAutoAdjustProbeAmbiance; } else { diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 8ed359fc0a..c94a4f7875 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -104,10 +104,7 @@ BOOL LLSidepanelAppearance::postBuild() childSetAction("edit_outfit_btn", boost::bind(&LLSidepanelAppearance::showOutfitEditPanel, this)); - // Don't filter outfits list on keypress - //mFilterEditor = getChild("Filter"); - mFilterEditor = findChild("Filter"); - // + mFilterEditor = getChild("Filter"); if (mFilterEditor) { mFilterEditor->setCommitCallback(boost::bind(&LLSidepanelAppearance::onFilterEdit, this, _2)); diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h index 75c6cc8edf..ed0ef60d47 100644 --- a/indra/newview/llsidepanelappearance.h +++ b/indra/newview/llsidepanelappearance.h @@ -33,10 +33,7 @@ #include "llinventory.h" #include "llpaneloutfitedit.h" -// Don't filter outfits list on keypress -//class LLFilterEditor; -class LLSearchEditor; -// +class LLFilterEditor; class LLCurrentlyWornFetchObserver; class LLPanelEditWearable; class LLViewerWearable; @@ -95,10 +92,7 @@ private: void toggleOutfitEditPanel(BOOL visible, BOOL disable_camera_switch = FALSE); void toggleWearableEditPanel(BOOL visible, LLViewerWearable* wearable = NULL, BOOL disable_camera_switch = FALSE); - // Don't filter outfits list on keypress - //LLFilterEditor* mFilterEditor; - LLSearchEditor* mFilterEditor; - // + LLFilterEditor* mFilterEditor; LLPanelOutfitsInventory* mPanelOutfitsInventory; LLPanelOutfitEdit* mOutfitEdit; LLPanelEditWearable* mEditWearable; diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index 89ec482d5c..5fd2650fed 100644 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llurlsimstring.cpp (was llsimurlstring.cpp) * @brief Handles "SLURL fragments" like Ahern/123/45 for * startup processing, login screen, prefs, etc. @@ -6,21 +6,21 @@ * $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$ */ @@ -40,7 +40,7 @@ const char* LLSLURL::SLURL_HTTP_SCHEME = "http"; const char* LLSLURL::SLURL_HTTPS_SCHEME = "https"; -const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife"; +const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife"; const char* LLSLURL::SLURL_SECONDLIFE_PATH = "secondlife"; const char* LLSLURL::SLURL_COM = "slurl.com"; // For DnD - even though www.slurl.com redirects to slurl.com in a browser, you can copy and drag @@ -58,486 +58,482 @@ const char* LLSLURL::SIM_LOCATION_LAST = "last"; // resolve a simstring from a slurl LLSLURL::LLSLURL(const std::string& slurl) { - // by default we go to agni. - mType = INVALID; + // by default we go to agni. + mType = INVALID; - if(slurl == SIM_LOCATION_HOME) - { - mType = HOME_LOCATION; - } - else if(slurl.empty() || (slurl == SIM_LOCATION_LAST)) - { - mType = LAST_LOCATION; - } - else - { - LLURI slurl_uri; - // parse the slurl as a uri - if(slurl.find(':') == std::string::npos) - { - // There may be no scheme ('secondlife:' etc.) passed in. In that case - // we want to normalize the slurl by putting the appropriate scheme - // in front of the slurl. So, we grab the appropriate slurl base - // from the grid manager which may be http://slurl.com/secondlife/ for maingrid, or - // https:///region/ for Standalone grid (the word region, not the region name) - // these slurls are typically passed in from the 'starting location' box on the login panel, - // where the user can type in /// - std::string fixed_slurl = LLGridManager::getInstance()->getSLURLBase(); + if (slurl.empty() || (slurl == SIM_LOCATION_LAST)) + { + mType = LAST_LOCATION; + } + else if (slurl == SIM_LOCATION_HOME) + { + mType = HOME_LOCATION; + } + else + { + LLURI slurl_uri; + // parse the slurl as a uri + if (slurl.find(':') == std::string::npos) + { + // There may be no scheme ('secondlife:' etc.) passed in. In that case + // we want to normalize the slurl by putting the appropriate scheme + // in front of the slurl. So, we grab the appropriate slurl base + // from the grid manager which may be http://slurl.com/secondlife/ for maingrid, or + // https:///region/ for Standalone grid (the word region, not the region name) + // these slurls are typically passed in from the 'starting location' box on the login panel, + // where the user can type in /// + std::string fixed_slurl = LLGridManager::getInstance()->getSLURLBase(); - // the slurl that was passed in might have a prepended /, or not. So, - // we strip off the prepended '/' so we don't end up with http://slurl.com/secondlife//// - // or some such. - - if(slurl[0] == '/') - { - fixed_slurl += slurl.substr(1); - } - else - { - fixed_slurl += slurl; - } - // We then load the slurl into a LLURI form - slurl_uri = LLURI(fixed_slurl); - } - else - { - // as we did have a scheme, implying a URI style slurl, we - // simply parse it as a URI - slurl_uri = LLURI(slurl); - } - - LLSD path_array = slurl_uri.pathArray(); - - // determine whether it's a maingrid URI or an Standalone/open style URI - // by looking at the scheme. If it's a 'secondlife:' slurl scheme or - // 'sl:' scheme, we know it's maingrid - - // At the end of this if/else block, we'll have determined the grid, - // and the slurl type (APP or LOCATION) - if(slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME) - { - // parse a maingrid style slurl. We know the grid is maingrid - // so grab it. - // A location slurl for maingrid (with the special schemes) can be in the form - // secondlife:///// - // or - // secondlife:///secondlife//// - // where if grid is empty, it specifies Agni - - // An app style slurl for maingrid can be - // secondlife:///app/ - // where an empty grid implies Agni - - // we'll start by checking the top of the 'path' which will be - // either 'app', 'secondlife', or . - - // default to maingrid - - mGrid = MAINGRID; - - if ((path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) || - (path_array[0].asString() == LLSLURL::SLURL_APP_PATH)) - { - // it's in the form secondlife:///(app|secondlife) - // so parse the grid name to derive the grid ID - if (!slurl_uri.hostName().empty()) - { - mGrid = LLGridManager::getInstance()->getGridId(slurl_uri.hostName()); - } - else if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) - { - // If the slurl is in the form secondlife:///secondlife/ form, - // then we are in fact on maingrid. - mGrid = MAINGRID; - } - else if(path_array[0].asString() == LLSLURL::SLURL_APP_PATH) - { - // for app style slurls, where no grid name is specified, assume the currently - // selected or logged in grid. - mGrid = LLGridManager::getInstance()->getGridId(); - } + // the slurl that was passed in might have a prepended /, or not. So, + // we strip off the prepended '/' so we don't end up with http://slurl.com/secondlife//// + // or some such. - if(mGrid.empty()) - { - // we couldn't find the grid in the grid manager, so bail - LL_WARNS("AppInit")<<"unable to find grid"</// + // or + // secondlife:///secondlife//// + // where if grid is empty, it specifies Agni + + // An app style slurl for maingrid can be + // secondlife:///app/ + // where an empty grid implies Agni + + // we'll start by checking the top of the 'path' which will be + // either 'app', 'secondlife', or . + + // default to maingrid + + mGrid = MAINGRID; + + if ((path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) || + (path_array[0].asString() == LLSLURL::SLURL_APP_PATH)) + { + // it's in the form secondlife:///(app|secondlife) + // so parse the grid name to derive the grid ID + if (!slurl_uri.hostName().empty()) + { + mGrid = LLGridManager::getInstance()->getGridId(slurl_uri.hostName()); + } + else if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) + { + // If the slurl is in the form secondlife:///secondlife/ form, + // then we are in fact on maingrid. + mGrid = MAINGRID; + } + else if(path_array[0].asString() == LLSLURL::SLURL_APP_PATH) + { + // for app style slurls, where no grid name is specified, assume the currently + // selected or logged in grid. + mGrid = LLGridManager::getInstance()->getGridId(); + } + + if (mGrid.empty()) + { + // we couldn't find the grid in the grid manager, so bail + LL_WARNS("AppInit")<<"unable to find grid"< or /app/, so it must be secondlife:// - // therefore the hostname will be the region name, and it's a location type - mType = LOCATION; - // 'normalize' it so the region name is in fact the head of the path_array - path_array.insert(0, slurl_uri.hostName()); + // therefore the hostname will be the region name, and it's a location type + mType = LOCATION; + // 'normalize' it so the region name is in fact the head of the path_array + path_array.insert(0, slurl_uri.hostName()); + } + } + } + else if ((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME) || + (slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) || + (slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME)) + { + // We're dealing with either a Standalone style slurl or slurl.com slurl + if ((slurl_uri.hostName() == LLSLURL::SLURL_COM) || + (slurl_uri.hostName() == LLSLURL::WWW_SLURL_COM) || + (slurl_uri.hostName() == LLSLURL::MAPS_SECONDLIFE_COM)) + { + // slurl.com implies maingrid + mGrid = MAINGRID; + } + else + { + // Don't try to match any old http:/// URL as a SLurl. + // SLE SLurls will have the grid hostname in the URL, so only + // match http URLs if the hostname matches the grid hostname + // (or its a slurl.com or maps.secondlife.com URL). + if ((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME || + slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) && + slurl_uri.hostName() != LLGridManager::getInstance()->getGrid()) + { + return; } - } - } - else if((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME) || - (slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) || - (slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME)) - { - // We're dealing with either a Standalone style slurl or slurl.com slurl - if ((slurl_uri.hostName() == LLSLURL::SLURL_COM) || - (slurl_uri.hostName() == LLSLURL::WWW_SLURL_COM) || - (slurl_uri.hostName() == LLSLURL::MAPS_SECONDLIFE_COM)) - { - // slurl.com implies maingrid - mGrid = MAINGRID; - } - else - { - // Don't try to match any old http:/// URL as a SLurl. - // SLE SLurls will have the grid hostname in the URL, so only - // match http URLs if the hostname matches the grid hostname - // (or its a slurl.com or maps.secondlife.com URL). - if ((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME || - slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) && - slurl_uri.hostName() != LLGridManager::getInstance()->getGrid()) - { - return; - } - // As it's a Standalone grid/open, we will always have a hostname, as Standalone/open style - // urls are properly formed, unlike the stinky maingrid style - mGrid = slurl_uri.hostName(); - } - if (path_array.size() == 0) - { - // um, we need a path... - return; - } - - // we need to normalize the urls so - // the path portion starts with the 'command' that we want to do - // it can either be region or app. - if ((path_array[0].asString() == LLSLURL::SLURL_REGION_PATH) || - (path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)) - { - // strip off 'region' or 'secondlife' - path_array.erase(0); - // it's a location - mType = LOCATION; - } - else if (path_array[0].asString() == LLSLURL::SLURL_APP_PATH) - { - mType = APP; - path_array.erase(0); - // leave app appended. - } - else - { - // not a valid https/http/x-grid-location-info slurl, so it'll likely just be a URL - return; - } - } - else - { - // invalid scheme, so bail - return; - } - - - if(path_array.size() == 0) - { - // we gotta have some stuff after the specifier as to whether it's a region or command - return; - } - - // now that we know whether it's an app slurl or a location slurl, - // parse the slurl into the proper data structures. - if(mType == APP) - { - // grab the app command type and strip it (could be a command to jump somewhere, - // or whatever ) - mAppCmd = path_array[0].asString(); - path_array.erase(0); - - // Grab the parameters - mAppPath = path_array; - // and the query - mAppQuery = slurl_uri.query(); - mAppQueryMap = slurl_uri.queryMap(); - return; - } - else if(mType == LOCATION) - { - // at this point, head of the path array should be [ , , , ] where x, y and z - // are collectively optional - // are optional + // As it's a Standalone grid/open, we will always have a hostname, as Standalone/open style + // urls are properly formed, unlike the stinky maingrid style + mGrid = slurl_uri.hostName(); + } + if (path_array.size() == 0) + { + // um, we need a path... + return; + } - mRegion = LLURI::unescape(path_array[0].asString()); + // we need to normalize the urls so + // the path portion starts with the 'command' that we want to do + // it can either be region or app. + if ((path_array[0].asString() == LLSLURL::SLURL_REGION_PATH) || + (path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)) + { + // strip off 'region' or 'secondlife' + path_array.erase(0); + // it's a location + mType = LOCATION; + } + else if (path_array[0].asString() == LLSLURL::SLURL_APP_PATH) + { + mType = APP; + path_array.erase(0); + // leave app appended. + } + else + { + // not a valid https/http/x-grid-location-info slurl, so it'll likely just be a URL + return; + } + } + else + { + // invalid scheme, so bail + return; + } - if(LLStringUtil::containsNonprintable(mRegion)) - { - LLStringUtil::stripNonprintable(mRegion); - } + if (path_array.size() == 0) + { + // we gotta have some stuff after the specifier as to whether it's a region or command + return; + } - path_array.erase(0); - - // parse the x, y, and optionally z - if(path_array.size() >= 2) - { - - mPosition = LLVector3(path_array); // this construction handles LLSD without all components (values default to 0.f) - if((F32(mPosition[VX]) < 0.f) || - (mPosition[VX] > REGION_WIDTH_METERS) || - (F32(mPosition[VY]) < 0.f) || - (mPosition[VY] > REGION_WIDTH_METERS) || - (F32(mPosition[VZ]) < 0.f) || - (mPosition[VZ] > REGION_HEIGHT_METERS)) - { - mType = INVALID; - return; - } - - } - else - { - // if x, y and z were not fully passed in, go to the middle of the region. - // teleport will adjust the actual location to make sure you're on the ground - // and such - mPosition = LLVector3(REGION_WIDTH_METERS/2, REGION_WIDTH_METERS/2, 0); - } - } - } + // now that we know whether it's an app slurl or a location slurl, + // parse the slurl into the proper data structures. + if (mType == APP) + { + // grab the app command type and strip it (could be a command to jump somewhere, + // or whatever ) + mAppCmd = path_array[0].asString(); + path_array.erase(0); + + // Grab the parameters + mAppPath = path_array; + // and the query + mAppQuery = slurl_uri.query(); + mAppQueryMap = slurl_uri.queryMap(); + return; + } + else if (mType == LOCATION) + { + // at this point, head of the path array should be [ , , , ] where x, y and z + // are collectively optional + // are optional + + mRegion = LLURI::unescape(path_array[0].asString()); + + if (LLStringUtil::containsNonprintable(mRegion)) + { + LLStringUtil::stripNonprintable(mRegion); + } + + path_array.erase(0); + + // parse the x, y, and optionally z + if (path_array.size() >= 2) + { + mPosition = LLVector3(path_array); // this construction handles LLSD without all components (values default to 0.f) + if ((F32(mPosition[VX]) < 0.f) || (mPosition[VX] > REGION_WIDTH_METERS) || + (F32(mPosition[VY]) < 0.f) || (mPosition[VY] > REGION_WIDTH_METERS) || + (F32(mPosition[VZ]) < 0.f) || (mPosition[VZ] > REGION_HEIGHT_METERS)) + { + mType = INVALID; + return; + } + } + else + { + // if x, y and z were not fully passed in, go to the middle of the region. + // teleport will adjust the actual location to make sure you're on the ground + // and such + mPosition = LLVector3(REGION_WIDTH_METERS / 2, REGION_WIDTH_METERS / 2, 0); + } + } + } } - // Create a slurl for the middle of the region -LLSLURL::LLSLURL(const std::string& grid, - const std::string& region) +LLSLURL::LLSLURL(const std::string& grid, const std::string& region) { - mGrid = grid; - mRegion = region; - mType = LOCATION; - mPosition = LLVector3((F64)REGION_WIDTH_METERS/2, (F64)REGION_WIDTH_METERS/2, 0); + mGrid = grid; + mRegion = region; + mType = LOCATION; + mPosition = LLVector3((F64)REGION_WIDTH_METERS / 2, (F64)REGION_WIDTH_METERS / 2, 0); } - - // create a slurl given the position. The position will be modded with the region // width handling global positions as well -LLSLURL::LLSLURL(const std::string& grid, - const std::string& region, - const LLVector3& position) +LLSLURL::LLSLURL(const std::string& grid, + const std::string& region, + const LLVector3& position) { - mGrid = grid; - mRegion = region; - S32 x = ll_round( (F32)fmod( position[VX], (F32)REGION_WIDTH_METERS ) ); - S32 y = ll_round( (F32)fmod( position[VY], (F32)REGION_WIDTH_METERS ) ); - S32 z = ll_round( (F32)position[VZ] ); - mType = LOCATION; - mPosition = LLVector3(x, y, z); + mGrid = grid; + mRegion = region; + S32 x = ll_round((F32)fmod(position[VX], (F32)REGION_WIDTH_METERS)); + S32 y = ll_round((F32)fmod(position[VY], (F32)REGION_WIDTH_METERS)); + S32 z = ll_round((F32)position[VZ]); + mType = LOCATION; + mPosition = LLVector3(x, y, z); } - // create a simstring -LLSLURL::LLSLURL(const std::string& region, - const LLVector3& position) +LLSLURL::LLSLURL(const std::string& region, + const LLVector3& position) { - *this = LLSLURL(LLGridManager::getInstance()->getGridId(), - region, position); + *this = LLSLURL(LLGridManager::getInstance()->getGridId(), region, position); } // create a slurl from a global position -LLSLURL::LLSLURL(const std::string& grid, - const std::string& region, - const LLVector3d& , // FIRE-30768: SLURL's don't work in VarRegions *unused param in SL builds* - const LLVector3d& global_position) +LLSLURL::LLSLURL(const std::string& grid, + const std::string& region, + const LLVector3d& , // FIRE-30768: SLURL's don't work in VarRegions *unused param in SL builds* + const LLVector3d& global_position) { - *this = LLSLURL(LLGridManager::getInstance()->getGridId(grid), - region, LLVector3(global_position.mdV[VX], - global_position.mdV[VY], - global_position.mdV[VZ])); + *this = LLSLURL(LLGridManager::getInstance()->getGridId(grid), region, + LLVector3(global_position.mdV[VX], global_position.mdV[VY], global_position.mdV[VZ])); } // create a slurl from a global position -LLSLURL::LLSLURL(const std::string& region, - const LLVector3d& region_origin, // FIRE-30768: SLURL's don't work in VarRegions - const LLVector3d& global_position) +LLSLURL::LLSLURL(const std::string& region, + const LLVector3d& region_origin, // FIRE-30768: SLURL's don't work in VarRegions + const LLVector3d& global_position) { - // FIRE-30768: SLURL's don't work in VarRegions - // *this = LLSLURL(LLGridManager::getInstance()->getGridId(), - // region, global_position); - *this = LLSLURL(LLGridManager::getInstance()->getGridId(), - region, - region_origin, - global_position); - // + // FIRE-30768: SLURL's don't work in VarRegions + // *this = LLSLURL(LLGridManager::getInstance()->getGridId(), + // region, global_position); + *this = LLSLURL(LLGridManager::getInstance()->getGridId(), + region, + region_origin, + global_position); + // } LLSLURL::LLSLURL(const std::string& command, const LLUUID&id, const std::string& verb) { - mType = APP; - mAppCmd = command; - mAppPath = LLSD::emptyArray(); - mAppPath.append(LLSD(id)); - mAppPath.append(LLSD(verb)); + mType = APP; + mAppCmd = command; + mAppPath = LLSD::emptyArray(); + mAppPath.append(LLSD(id)); + mAppPath.append(LLSD(verb)); } - std::string LLSLURL::getSLURLString() const { - switch(mType) - { - case HOME_LOCATION: - return SIM_LOCATION_HOME; - case LAST_LOCATION: - return SIM_LOCATION_LAST; - case LOCATION: - { - // lookup the grid - S32 x = ll_round( (F32)mPosition[VX] ); - S32 y = ll_round( (F32)mPosition[VY] ); - S32 z = ll_round( (F32)mPosition[VZ] ); -// return LLGridManager::getInstance()->getSLURLBase(mGrid) + -// LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z); + switch (mType) + { + case HOME_LOCATION: + return SIM_LOCATION_HOME; + case LAST_LOCATION: + return SIM_LOCATION_LAST; + case LOCATION: + { + // lookup the grid + S32 x = ll_round((F32)mPosition[VX]); + S32 y = ll_round((F32)mPosition[VY]); + S32 z = ll_round((F32)mPosition[VZ]); +// return LLGridManager::getInstance()->getSLURLBase(mGrid) + +// LLURI::escape(mRegion) + llformat("/%d/%d/%d", x, y, z); // [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d - return LLGridManager::getInstance()->getSLURLBase(mGrid) + - ( ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) || (!RlvUtil::isNearbyRegion(mRegion))) - ? (LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z)) : RlvStrings::getString(RlvStringKeys::Hidden::Region) ); + return LLGridManager::getInstance()->getSLURLBase(mGrid) + + ( ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) || (!RlvUtil::isNearbyRegion(mRegion))) + ? (LLURI::escape(mRegion) + llformat("/%d/%d/%d", x, y, z)) : RlvStrings::getString(RlvStringKeys::Hidden::Region) ); // [/RLVa:KB] - } - case APP: - { - std::ostringstream app_url; - app_url << LLGridManager::getInstance()->getAppSLURLBase() << "/" << mAppCmd; - for(LLSD::array_const_iterator i = mAppPath.beginArray(); - i != mAppPath.endArray(); - i++) - { - app_url << "/" << i->asString(); - } - if(mAppQuery.length() > 0) - { - app_url << "?" << mAppQuery; - } - return app_url.str(); - } - default: - LL_WARNS("AppInit") << "Unexpected SLURL type for SLURL string" << (int)mType << LL_ENDL; - return std::string(); - } + } + case APP: + { + std::ostringstream app_url; + app_url << LLGridManager::getInstance()->getAppSLURLBase() << "/" << mAppCmd; + for (LLSD::array_const_iterator i = mAppPath.beginArray(); + i != mAppPath.endArray(); + i++) + { + app_url << "/" << i->asString(); + } + if (mAppQuery.length() > 0) + { + app_url << "?" << mAppQuery; + } + return app_url.str(); + } + default: + LL_WARNS("AppInit") << "Unexpected SLURL type for SLURL string" << (int)mType << LL_ENDL; + return std::string(); + } } std::string LLSLURL::getLoginString() const { - - std::stringstream unescaped_start; - switch(mType) - { - case LOCATION: - unescaped_start << "uri:" - << mRegion << "&" - << ll_round(mPosition[0]) << "&" - << ll_round(mPosition[1]) << "&" - << ll_round(mPosition[2]); - break; - case HOME_LOCATION: - unescaped_start << "home"; - break; - case LAST_LOCATION: - unescaped_start << "last"; - break; - default: - LL_WARNS("AppInit") << "Unexpected SLURL type ("<<(int)mType <<")for login string"<< LL_ENDL; - break; - } - return xml_escape_string(unescaped_start.str()); + std::stringstream unescaped_start; + switch (mType) + { + case LOCATION: + unescaped_start << "uri:" + << mRegion << "&" + << ll_round(mPosition[0]) << "&" + << ll_round(mPosition[1]) << "&" + << ll_round(mPosition[2]); + break; + case HOME_LOCATION: + unescaped_start << "home"; + break; + case LAST_LOCATION: + unescaped_start << "last"; + break; + default: + LL_WARNS("AppInit") << "Unexpected SLURL type (" << (int)mType << ")for login string" << LL_ENDL; + break; + } + return xml_escape_string(unescaped_start.str()); } -bool LLSLURL::operator==(const LLSLURL& rhs) +bool LLSLURL::operator ==(const LLSLURL& rhs) { - if(rhs.mType != mType) return false; - switch(mType) - { - case LOCATION: - return ((mGrid == rhs.mGrid) && - (mRegion == rhs.mRegion) && - (mPosition == rhs.mPosition)); - case APP: - return getSLURLString() == rhs.getSLURLString(); - - case HOME_LOCATION: - case LAST_LOCATION: - return true; - default: - return false; - } + if (rhs.mType != mType) + return false; + + switch (mType) + { + case LOCATION: + return (mGrid == rhs.mGrid) && + (mRegion == rhs.mRegion) && + (mPosition == rhs.mPosition); + + case APP: + return getSLURLString() == rhs.getSLURLString(); + + case HOME_LOCATION: + case LAST_LOCATION: + return true; + + default: + return false; + } } bool LLSLURL::operator !=(const LLSLURL& rhs) { - return !(*this == rhs); + return !(*this == rhs); } std::string LLSLURL::getLocationString() const { - return llformat("%s/%d/%d/%d", - mRegion.c_str(), - (int)ll_round(mPosition[0]), - (int)ll_round(mPosition[1]), - (int)ll_round(mPosition[2])); + return llformat("%s/%d/%d/%d", + mRegion.c_str(), + (int)ll_round(mPosition[0]), + (int)ll_round(mPosition[1]), + (int)ll_round(mPosition[2])); } // static -const std::string LLSLURL::typeName[NUM_SLURL_TYPES] = +const std::string LLSLURL::typeName[NUM_SLURL_TYPES] = { - "INVALID", - "LOCATION", - "HOME_LOCATION", - "LAST_LOCATION", - "APP", - "HELP" + "INVALID", + "LOCATION", + "HOME_LOCATION", + "LAST_LOCATION", + "APP", + "HELP", + "EMPTY" }; - + std::string LLSLURL::getTypeString(SLURL_TYPE type) { - std::string name; - if ( type >= INVALID && type < NUM_SLURL_TYPES ) - { - name = LLSLURL::typeName[type]; - } - else - { - name = llformat("Out of Range (%d)",type); - } - return name; + std::string name; + if (type >= INVALID && type < NUM_SLURL_TYPES) + { + name = LLSLURL::typeName[type]; + } + else + { + name = llformat("Out of Range (%d)", type); + } + return name; } - std::string LLSLURL::asString() const { std::ostringstream result; result - << " mType: " << LLSLURL::getTypeString(mType) - << " mGrid: " + getGrid() - << " mRegion: " + getRegion() - << " mPosition: " << mPosition - << " mAppCmd:" << getAppCmd() - << " mAppPath:" + getAppPath().asString() - << " mAppQueryMap:" + getAppQueryMap().asString() - << " mAppQuery: " + getAppQuery() - ; - + << " mType: " << LLSLURL::getTypeString(mType) + << " mGrid: " + getGrid() + << " mRegion: " + getRegion() + << " mPosition: " << mPosition + << " mAppCmd:" << getAppCmd() + << " mAppPath:" + getAppPath().asString() + << " mAppQueryMap:" + getAppQueryMap().asString() + << " mAppQuery: " + getAppQuery() + ; + return result.str(); } - diff --git a/indra/newview/llslurl.h b/indra/newview/llslurl.h index fd0db1837c..d53383e421 100644 --- a/indra/newview/llslurl.h +++ b/indra/newview/llslurl.h @@ -55,13 +55,14 @@ public: static const char* SLURL_REGION_PATH; // if you modify this enumeration, update typeName as well - enum SLURL_TYPE { - INVALID, + enum SLURL_TYPE { + INVALID, LOCATION, HOME_LOCATION, LAST_LOCATION, APP, HELP, + EMPTY, NUM_SLURL_TYPES // must be last }; diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 2816671b8a..cea488710d 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -863,10 +863,8 @@ void LLSpatialGroup::rebound() if (controlAvatar && controlAvatar->mDrawable && controlAvatar->mControlAVBridge && - controlAvatar->mControlAVBridge->mOctree)// FIRE-33367 toggling animesh state off causes a crash + controlAvatar->mControlAVBridge->mOctree) { - llassert(controlAvatar->mControlAVBridge->mOctree); - LLSpatialGroup* root = (LLSpatialGroup*)controlAvatar->mControlAVBridge->mOctree->getListener(0); if (this == root) { @@ -879,7 +877,7 @@ void LLSpatialGroup::rebound() } } -void LLSpatialGroup::destroyGLState(bool keep_occlusion) +void LLSpatialGroup::destroyGLState(bool keep_occlusion) { // Reset VB during TP bool is_tree_group = getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_TREE; @@ -1346,17 +1344,8 @@ void drawBox(const LLVector4a& c, const LLVector4a& r) void drawBoxOutline(const LLVector3& pos, const LLVector3& size) { - - llassert(pos.isFinite()); - llassert(size.isFinite()); - - llassert(!llisnan(pos.mV[0])); - llassert(!llisnan(pos.mV[1])); - llassert(!llisnan(pos.mV[2])); - - llassert(!llisnan(size.mV[0])); - llassert(!llisnan(size.mV[1])); - llassert(!llisnan(size.mV[2])); + if (!pos.isFinite() || !size.isFinite()) + return; LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1)); LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1)); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index ef6a6ce902..24fd516bd6 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2176,9 +2176,6 @@ bool idle_startup() gXferManager->registerCallbacks(gMessageSystem); display_startup(); - LLGLTFMaterialList::registerCallbacks(); - display_startup(); - LLStartUp::initNameCache(); display_startup(); @@ -3365,6 +3362,34 @@ void login_callback(S32 option, void *userdata) } } +void release_notes_coro(const std::string url) +{ + if (url.empty()) + { + return; + } + + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("releaseNotesCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + + httpOpts->setHeadersOnly(true); // only making sure it isn't 404 or something like that + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + return; + } + + LLWeb::loadURLInternal(url); +} + /** * Check if user is running a new version of the viewer. * Display the Release Notes if it's not overriden by the "UpdaterShowReleaseNotes" setting. @@ -3397,7 +3422,8 @@ void show_release_notes_if_required() LLEventPumps::instance().obtain("relnotes").listen( "showrelnotes", [](const LLSD& url) { - LLWeb::loadURLInternal(url.asString()); + LLCoros::instance().launch("releaseNotesCoro", + boost::bind(&release_notes_coro, url.asString())); return false; }); } @@ -3405,7 +3431,9 @@ void show_release_notes_if_required() #endif // LL_RELEASE_FOR_DOWNLOAD { LLSD info(LLAppViewer::instance()->getViewerInfo()); - LLWeb::loadURLInternal(info["VIEWER_RELEASE_NOTES_URL"]); + std::string url = info["VIEWER_RELEASE_NOTES_URL"].asString(); + LLCoros::instance().launch("releaseNotesCoro", + boost::bind(&release_notes_coro, url)); } release_notes_shown = true; } diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index e93261f406..5e7134851e 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -350,6 +350,15 @@ BOOL LLStatusBar::postBuild() LLHints::getInstance()->registerHintTarget("linden_balance", getChild("balance_bg")->getHandle()); gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&LLStatusBar::onVolumeChanged, this, _2)); + // Fix LL voice disabled on 2nd instance nonsense + //gSavedSettings.getControl("EnableVoiceChat")->getSignal()->connect(boost::bind(&LLStatusBar::onVoiceChanged, this, _2)); + + //if (!gSavedSettings.getBOOL("EnableVoiceChat") && LLAppViewer::instance()->isSecondInstance()) + //{ + // // Indicate that second instance started without sound + // mBtnVolume->setImageUnselected(LLUI::getUIImage("VoiceMute_Off")); + //} + // // FIRE-19697: Add setting to disable graphics preset menu popup on mouse over gSavedSettings.getControl("FSStatusBarMenuButtonPopupOnRollover")->getSignal()->connect(boost::bind(&LLStatusBar::onPopupRolloverChanged, this, _2)); @@ -1125,6 +1134,18 @@ void LLStatusBar::onVolumeChanged(const LLSD& newvalue) refresh(); } +// Fix LL voice disabled on 2nd instance nonsense +//void LLStatusBar::onVoiceChanged(const LLSD& newvalue) +//{ +// if (newvalue.asBoolean()) +// { +// // Second instance starts with "VoiceMute_Off" icon, fix it +// mBtnVolume->setImageUnselected(LLUI::getUIImage("Audio_Off")); +// } +// refresh(); +//} +// + void LLStatusBar::onUpdateFilterTerm() { LLWString searchValue = utf8str_to_wstring( mFilterEdit->getValue() ); diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 81d427cfd4..f8d5b7deeb 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -164,13 +164,12 @@ private: void onClickBuyCurrency(); void onVolumeChanged(const LLSD& newvalue); + //void onVoiceChanged(const LLSD& newvalue); // Fix LL voice disabled on 2nd instance nonsense void onMouseEnterPresetsCamera(); void onMouseEnterPresets(); void onMouseEnterVolume(); void onMouseEnterNearbyMedia(); - // Does not exist 15-02-2021 - //void onClickScreen(S32 x, S32 y); static void onClickStreamToggle(void* data); // Media/Stream separation static void onClickMediaToggle(void* data); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 376396856c..8a5aee64b7 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -83,9 +83,11 @@ //static bool get_is_predefined_texture(LLUUID asset_id) { - if (asset_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture")) - || asset_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID")) - || asset_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID")) + if (asset_id == DEFAULT_OBJECT_TEXTURE + || asset_id == DEFAULT_OBJECT_SPECULAR + || asset_id == DEFAULT_OBJECT_NORMAL + || asset_id == BLANK_OBJECT_NORMAL + || asset_id == IMG_WHITE || asset_id == LLUUID(SCULPT_DEFAULT_TEXTURE)) { return true; @@ -152,7 +154,8 @@ LLFloaterTexturePicker::LLFloaterTexturePicker( PermissionMask immediate_filter_perm_mask, PermissionMask dnd_filter_perm_mask, BOOL can_apply_immediately, - LLUIImagePtr fallback_image) + LLUIImagePtr fallback_image, + EPickInventoryType pick_type) : LLFloater(LLSD()), mOwner( owner ), mImageAssetID( image_asset_id ), @@ -183,7 +186,7 @@ LLFloaterTexturePicker::LLFloaterTexturePicker( mSetImageAssetIDCallback(NULL), mOnUpdateImageStatsCallback(NULL), mBakeTextureEnabled(FALSE), - mInventoryPickType(LLTextureCtrl::PICK_TEXTURE) + mInventoryPickType(pick_type) { mCanApplyImmediately = can_apply_immediately; buildFromFile("floater_texture_ctrl.xml"); @@ -235,7 +238,7 @@ void LLFloaterTexturePicker::setImageID(const LLUUID& image_id, bool set_selecti LLInventoryItem* itemp = gInventory.getItem(inv_view->getUUID()); - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL + if (mInventoryPickType == PICK_MATERIAL && mImageAssetID == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID && itemp && itemp->getAssetUUID().isNull()) { @@ -304,7 +307,7 @@ void LLFloaterTexturePicker::setImageID(const LLUUID& image_id, bool set_selecti void LLFloaterTexturePicker::setImageIDFromItem(const LLInventoryItem* itemp, bool set_selection) { LLUUID asset_id = itemp->getAssetUUID(); - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL && asset_id.isNull()) + if (mInventoryPickType == PICK_MATERIAL && asset_id.isNull()) { // If an inventory item has a null asset, consider it a valid blank material(gltf) asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID; @@ -465,11 +468,11 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop( bool is_material = cargo_type == DAD_MATERIAL; bool allow_dnd = false; - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + if (mInventoryPickType == PICK_MATERIAL) { allow_dnd = is_material; } - else if (mInventoryPickType == LLTextureCtrl::PICK_TEXTURE) + else if (mInventoryPickType == PICK_TEXTURE) { allow_dnd = is_texture || is_mesh; } @@ -671,9 +674,7 @@ BOOL LLFloaterTexturePicker::postBuild() // don't put keyboard focus on selected item, because the selection callback // will assume that this was user input - - - if(!mImageAssetID.isNull()) + if(!mImageAssetID.isNull() || mInventoryPickType == PICK_MATERIAL) { mInventoryPanel->setSelection(findItemID(mImageAssetID, FALSE), TAKE_FOCUS_NO); } @@ -725,7 +726,7 @@ void LLFloaterTexturePicker::draw() mGLTFMaterial = NULL; if (mImageAssetID.notNull()) { - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + if (mInventoryPickType == PICK_MATERIAL) { mGLTFMaterial = (LLFetchedGLTFMaterial*) gGLTFMaterialList.getMaterial(mImageAssetID); llassert(mGLTFMaterial == nullptr || dynamic_cast(gGLTFMaterialList.getMaterial(mImageAssetID)) != nullptr); @@ -851,27 +852,43 @@ void LLFloaterTexturePicker::draw() const LLUUID& LLFloaterTexturePicker::findItemID(const LLUUID& asset_id, BOOL copyable_only, BOOL ignore_library) { - LLUUID loockup_id = asset_id; - if (loockup_id.isNull()) + if (asset_id.isNull()) { - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) - { - loockup_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID; - } - else - { - return LLUUID::null; - } + // null asset id means, no material or texture assigned + return LLUUID::null; } + LLUUID loockup_id = asset_id; + if (mInventoryPickType == PICK_MATERIAL && loockup_id == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID) + { + // default asset id means we are looking for an inventory item with a default asset UUID (null) + loockup_id = LLUUID::null; + } + LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(loockup_id); - gInventory.collectDescendentsIf(LLUUID::null, - cats, - items, - LLInventoryModel::INCLUDE_TRASH, - asset_id_matches); + + if (loockup_id.isNull()) + { + // looking for a material with a null id, null id is shared by a lot + // of objects as a default value, so have to filter by type as well + LLAssetIDAndTypeMatches matches(loockup_id, LLAssetType::AT_MATERIAL); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + matches); + } + else + { + LLAssetIDMatches asset_id_matches(loockup_id); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + } + if (items.size()) { @@ -939,7 +956,7 @@ void LLFloaterTexturePicker::commitCallback(LLTextureCtrl::ETexturePickOp op) LLInventoryItem* itemp = gInventory.getItem(inv_view->getUUID()); - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL + if (mInventoryPickType == PICK_MATERIAL && mImageAssetID == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID && itemp && itemp->getAssetUUID().isNull()) { @@ -1185,15 +1202,15 @@ void LLFloaterTexturePicker::onBtnAdd(void* userdata) { LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)userdata; - if (self->mInventoryPickType == LLTextureCtrl::PICK_TEXTURE_MATERIAL) + if (self->mInventoryPickType == PICK_TEXTURE_MATERIAL) { LLFilePickerReplyThread::startPicker(boost::bind(&onPickerCallback, _1, self->getHandle()), LLFilePicker::FFLOAD_MATERIAL_TEXTURE, true); } - else if (self->mInventoryPickType == LLTextureCtrl::PICK_TEXTURE) + else if (self->mInventoryPickType == PICK_TEXTURE) { LLFilePickerReplyThread::startPicker(boost::bind(&onPickerCallback, _1, self->getHandle()), LLFilePicker::FFLOAD_IMAGE, true); } - else if (self->mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + else if (self->mInventoryPickType == PICK_MATERIAL) { LLFilePickerReplyThread::startPicker(boost::bind(&onPickerCallback, _1, self->getHandle()), LLFilePicker::FFLOAD_MATERIAL, true); } @@ -1480,7 +1497,7 @@ void LLFloaterTexturePicker::changeMode() //getChild("hide_base_mesh_region")->setVisible(FALSE);// index == 2 ? TRUE : FALSE); // Does not exist 11-10-2023 bool pipette_visible = (index == PICKER_INVENTORY) - && (mInventoryPickType != LLTextureCtrl::PICK_MATERIAL); + && (mInventoryPickType != PICK_MATERIAL); mPipetteBtn->setVisible(pipette_visible); if (index == PICKER_BAKE) @@ -1543,16 +1560,16 @@ void LLFloaterTexturePicker::refreshLocalList() { mLocalScrollCtrl->clearRows(); - if (mInventoryPickType == LLTextureCtrl::PICK_TEXTURE_MATERIAL) + if (mInventoryPickType == PICK_TEXTURE_MATERIAL) { LLLocalBitmapMgr::getInstance()->feedScrollList(mLocalScrollCtrl); LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(mLocalScrollCtrl); } - else if (mInventoryPickType == LLTextureCtrl::PICK_TEXTURE) + else if (mInventoryPickType == PICK_TEXTURE) { LLLocalBitmapMgr::getInstance()->feedScrollList(mLocalScrollCtrl); } - else if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + else if (mInventoryPickType == PICK_MATERIAL) { LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(mLocalScrollCtrl); } @@ -1562,18 +1579,18 @@ void LLFloaterTexturePicker::refreshInventoryFilter() { U32 filter_types = 0x0; - if (mInventoryPickType == LLTextureCtrl::PICK_TEXTURE_MATERIAL) + if (mInventoryPickType == PICK_TEXTURE_MATERIAL) { filter_types |= 0x1 << LLInventoryType::IT_TEXTURE; filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT; filter_types |= 0x1 << LLInventoryType::IT_MATERIAL; } - else if (mInventoryPickType == LLTextureCtrl::PICK_TEXTURE) + else if (mInventoryPickType == PICK_TEXTURE) { filter_types |= 0x1 << LLInventoryType::IT_TEXTURE; filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT; } - else if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + else if (mInventoryPickType == PICK_MATERIAL) { filter_types |= 0x1 << LLInventoryType::IT_MATERIAL; } @@ -1625,13 +1642,13 @@ void LLFloaterTexturePicker::setBakeTextureEnabled(BOOL enabled) onModeSelect(0, this); } -void LLFloaterTexturePicker::setInventoryPickType(LLTextureCtrl::EPickInventoryType type) +void LLFloaterTexturePicker::setInventoryPickType(EPickInventoryType type) { mInventoryPickType = type; refreshLocalList(); refreshInventoryFilter(); - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + if (mInventoryPickType == PICK_MATERIAL) { getChild("Pipette")->setVisible(false); } @@ -1647,7 +1664,7 @@ void LLFloaterTexturePicker::setInventoryPickType(LLTextureCtrl::EPickInventoryT setTitle(pick + mLabel); } - else if(mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + else if(mInventoryPickType == PICK_MATERIAL) { setTitle(getString("pick_material")); } @@ -1655,6 +1672,12 @@ void LLFloaterTexturePicker::setInventoryPickType(LLTextureCtrl::EPickInventoryT { setTitle(getString("pick_texture")); } + + // refresh selection + if (!mImageAssetID.isNull() || mInventoryPickType == PICK_MATERIAL) + { + mInventoryPanel->setSelection(findItemID(mImageAssetID, FALSE), TAKE_FOCUS_NO); + } } void LLFloaterTexturePicker::setImmediateFilterPermMask(PermissionMask mask) @@ -1689,16 +1712,16 @@ void LLFloaterTexturePicker::onPickerCallback(const std::vector& fi LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)handle.get(); self->mLocalScrollCtrl->clearRows(); - if (self->mInventoryPickType == LLTextureCtrl::PICK_TEXTURE_MATERIAL) + if (self->mInventoryPickType == PICK_TEXTURE_MATERIAL) { LLLocalBitmapMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); } - else if (self->mInventoryPickType == LLTextureCtrl::PICK_TEXTURE) + else if (self->mInventoryPickType == PICK_TEXTURE) { LLLocalBitmapMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); } - else if (self->mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + else if (self->mInventoryPickType == PICK_MATERIAL) { LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); } @@ -1711,7 +1734,7 @@ void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te ) if (inventory_item_id.notNull()) { LLToolPipette::getInstance()->setResult(TRUE, ""); - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + if (mInventoryPickType == PICK_MATERIAL) { // tes have no data about material ids // Plus gltf materials are layered with overrides, @@ -1778,8 +1801,7 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p) mCaptionHeight = p.show_caption ? BTN_HEIGHT_SMALL : 0; // leave some room underneath the image for the caption // Default of defaults is white image for diff tex // - LLUUID whiteImage( gSavedSettings.getString( "UIImgWhiteUUID" ) ); - setBlankImageAssetID( whiteImage ); + setBlankImageAssetID(IMG_WHITE); setAllowNoTexture(p.allow_no_texture); setCanApplyImmediately(p.can_apply_immediately); @@ -1983,7 +2005,8 @@ void LLTextureCtrl::showPicker(BOOL take_focus) mImmediateFilterPermMask, mDnDFilterPermMask, mCanApplyImmediately, - mFallbackImage); + mFallbackImage, + mInventoryPickType); mFloaterHandle = floaterp->getHandle(); LLFloaterTexturePicker* texture_floaterp = dynamic_cast(floaterp); @@ -2001,7 +2024,6 @@ void LLTextureCtrl::showPicker(BOOL take_focus) texture_floaterp->setSetImageAssetIDCallback(boost::bind(&LLTextureCtrl::setImageAssetID, this, _1)); texture_floaterp->setBakeTextureEnabled(mBakeTextureEnabled); - texture_floaterp->setInventoryPickType(mInventoryPickType); } LLFloater* root_floater = gFloaterView->getParentFloater(this); @@ -2064,7 +2086,7 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask) if (!mOpenTexPreview) { showPicker(FALSE); - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + if (mInventoryPickType == PICK_MATERIAL) { //grab materials first... LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL)); @@ -2274,11 +2296,11 @@ BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, bool is_material = cargo_type == DAD_MATERIAL; bool allow_dnd = false; - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + if (mInventoryPickType == PICK_MATERIAL) { allow_dnd = is_material; } - else if (mInventoryPickType == LLTextureCtrl::PICK_TEXTURE) + else if (mInventoryPickType == PICK_TEXTURE) { allow_dnd = is_texture || is_mesh; } @@ -2344,7 +2366,7 @@ void LLTextureCtrl::draw() if (texture.isNull()) { - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + if (mInventoryPickType == PICK_MATERIAL) { LLPointer material = gGLTFMaterialList.getMaterial(mImageAssetID); if (material) @@ -2512,7 +2534,7 @@ BOOL LLTextureCtrl::doDrop(LLInventoryItem* item) // no callback installed, so just set the image ids and carry on. LLUUID asset_id = item->getAssetUUID(); - if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL && asset_id.isNull()) + if (mInventoryPickType == PICK_MATERIAL && asset_id.isNull()) { // If an inventory material has a null asset, consider it a valid blank material(gltf) asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID; diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 77b4565da1..aae52ddcca 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -73,6 +73,13 @@ enum LLPickerSource PICKER_UNKNOWN, // on cancel, default ids }; +typedef enum e_pick_inventory_type +{ + PICK_TEXTURE_MATERIAL = 0, + PICK_TEXTURE = 1, + PICK_MATERIAL = 2, +} EPickInventoryType; + ////////////////////////////////////////////////////////////////////////////////////////// // LLTextureCtrl @@ -88,13 +95,6 @@ public: TEXTURE_CANCEL } ETexturePickOp; - typedef enum e_pick_inventory_type - { - PICK_TEXTURE_MATERIAL = 0, - PICK_TEXTURE = 1, - PICK_MATERIAL = 2, - } EPickInventoryType; - public: struct Params : public LLInitParam::Block { @@ -293,7 +293,7 @@ private: S32 mLabelWidth; bool mOpenTexPreview; bool mBakeTextureEnabled; - LLTextureCtrl::EPickInventoryType mInventoryPickType; + EPickInventoryType mInventoryPickType; // Mask texture if desired BOOL mIsMasked; @@ -323,8 +323,8 @@ public: PermissionMask immediate_filter_perm_mask, PermissionMask dnd_filter_perm_mask, BOOL can_apply_immediately, - LLUIImagePtr fallback_image_name - ); + LLUIImagePtr fallback_image_name, + EPickInventoryType pick_type); virtual ~LLFloaterTexturePicker(); @@ -398,7 +398,7 @@ public: void setLocalTextureEnabled(BOOL enabled); void setBakeTextureEnabled(BOOL enabled); - void setInventoryPickType(LLTextureCtrl::EPickInventoryType type); + void setInventoryPickType(EPickInventoryType type); void setImmediateFilterPermMask(PermissionMask mask); static void onPickerCallback(const std::vector& filenames, LLHandle handle); @@ -464,7 +464,7 @@ private: bool mLimitsSet; S32 mMaxDim; S32 mMinDim; - LLTextureCtrl::EPickInventoryType mInventoryPickType; + EPickInventoryType mInventoryPickType; texture_selected_callback mTextureSelectedCallback; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 16a8d3d394..53a85b7126 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -352,13 +352,13 @@ private: } // Threads: Tid - virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) + virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32 request_id) { LL_PROFILE_ZONE_SCOPED; LLTextureFetchWorker* worker = mFetcher->getWorker(mID); if (worker) { - worker->callbackDecoded(success, raw, aux); + worker->callbackDecoded(success, raw, aux, request_id); } } private: @@ -402,7 +402,7 @@ public: void callbackCacheWrite(bool success); // Threads: Tid - void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux); + void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux, S32 decode_id); // Threads: T* void setGetStatus(LLCore::HttpStatus status, const std::string& reason) @@ -1961,8 +1961,22 @@ bool LLTextureFetchWorker::doWork(S32 param) setState(DECODE_IMAGE_UPDATE); LL_DEBUGS(LOG_TXT) << mID << ": Decoding. Bytes: " << mFormattedImage->getDataSize() << " Discard: " << discard << " All Data: " << mHaveAllData << LL_ENDL; - mDecodeHandle = LLAppViewer::getImageDecodeThread()->decodeImage(mFormattedImage, discard, mNeedsAux, - new DecodeResponder(mFetcher, mID, this)); + + // In case worked manages to request decode, be shut down, + // then init and request decode again with first decode + // still in progress, assign a sufficiently unique id + mDecodeHandle = LLAppViewer::getImageDecodeThread()->decodeImage(mFormattedImage, + discard, + mNeedsAux, + new DecodeResponder(mFetcher, mID, this)); + if (mDecodeHandle == 0) + { + // Abort, failed to put into queue. + // Happens if viewer is shutting down + setState(DONE); + LL_DEBUGS(LOG_TXT) << mID << " DECODE_IMAGE abort: failed to post for decoding" << LL_ENDL; + return true; + } // fall though } @@ -2530,16 +2544,24 @@ void LLTextureFetchWorker::callbackCacheWrite(bool success) ////////////////////////////////////////////////////////////////////////////// // Threads: Tid -void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux) +void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux, S32 decode_id) { LLMutexLock lock(&mWorkMutex); // +Mw if (mDecodeHandle == 0) { return; // aborted, ignore } + if (mDecodeHandle != decode_id) + { + // Queue doesn't support canceling old requests. + // This shouldn't normally happen, but in case it's possible that a worked + // will request decode, be aborted, reinited then start a new decode + LL_DEBUGS(LOG_TXT) << mID << " received obsolete decode's callback" << LL_ENDL; + return; // ignore + } if (mState != DECODE_IMAGE_UPDATE) { -// LL_WARNS(LOG_TXT) << "Decode callback for " << mID << " with state = " << mState << LL_ENDL; + LL_DEBUGS(LOG_TXT) << "Decode callback for " << mID << " with state = " << mState << LL_ENDL; mDecodeHandle = 0; return; } diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp index 8990797286..977d39a5e6 100644 --- a/indra/newview/lltinygltfhelper.cpp +++ b/indra/newview/lltinygltfhelper.cpp @@ -178,6 +178,7 @@ LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tiny { rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component); rawImage->verticalFlip(); + rawImage->optimizeAwayAlpha(); } return rawImage; diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index a7c469bd3d..6a115f4021 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -60,7 +60,12 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llworld.h" -#include "llpanelface.h" +// switchable edit texture/materials panel +// #include "llpanelface.h" +#include "llmaterial.h" +#include "llmaterialmgr.h" +// + #include "lluiusage.h" // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) #include "rlvactions.h" @@ -1080,10 +1085,64 @@ BOOL LLToolDragAndDrop::handleDropMaterialProtections(LLViewerObject* hit_obj, return TRUE; } +void set_texture_to_material(LLViewerObject* hit_obj, + S32 hit_face, + const LLUUID& asset_id, + LLGLTFMaterial::TextureInfo drop_channel) +{ + LLTextureEntry* te = hit_obj->getTE(hit_face); + if (te) + { + LLPointer material = te->getGLTFMaterialOverride(); + + // make a copy to not invalidate existing + // material for multiple objects + if (material.isNull()) + { + // Start with a material override which does not make any changes + material = new LLGLTFMaterial(); + } + else + { + material = new LLGLTFMaterial(*material); + } + + switch (drop_channel) + { + case LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR: + default: + { + material->setBaseColorId(asset_id); + } + break; + + case LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS: + { + material->setOcclusionRoughnessMetallicId(asset_id); + } + break; + + case LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE: + { + material->setEmissiveId(asset_id); + } + break; + + case LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL: + { + material->setNormalId(asset_id); + } + break; + } + LLGLTFMaterialList::queueModify(hit_obj, hit_face, material); + } +} + void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj, LLInventoryItem* item, LLToolDragAndDrop::ESource source, - const LLUUID& src_id) + const LLUUID& src_id, + bool remove_pbr) { if (!item) { @@ -1100,28 +1159,46 @@ void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj, break; } } - if (!has_non_pbr_faces) + + if (has_non_pbr_faces || remove_pbr) { - return; + BOOL res = handleDropMaterialProtections(hit_obj, item, source, src_id); + if (!res) + { + return; + } } LLUUID asset_id = item->getAssetUUID(); - BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id); - if (!success) - { - return; - } + + // Overrides require textures to be copy and transfer free + LLPermissions item_permissions = item->getPermissions(); + bool allow_adding_to_override = item_permissions.allowOperationBy(PERM_COPY, gAgent.getID()); + allow_adding_to_override &= item_permissions.allowOperationBy(PERM_TRANSFER, gAgent.getID()); + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(asset_id); add(LLStatViewer::EDIT_TEXTURE, 1); for( S32 face = 0; face < num_faces; face++ ) { - if (hit_obj->getRenderMaterialID(face).isNull()) + if (remove_pbr) { - // update viewer side image in anticipation of update from simulator + hit_obj->setRenderMaterialID(face, LLUUID::null); hit_obj->setTEImage(face, image); dialog_refresh_all(); } + else if (hit_obj->getRenderMaterialID(face).isNull()) + { + // update viewer side + hit_obj->setTEImage(face, image); + dialog_refresh_all(); + } + else if (allow_adding_to_override) + { + set_texture_to_material(hit_obj, face, asset_id, LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR); + } } + // send the update to the simulator + LLGLTFMaterialList::flushUpdates(nullptr); hit_obj->sendTEUpdate(); } @@ -1269,21 +1346,13 @@ void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj, dialog_refresh_all(); } -/* -void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item) -{ - if (hit_face == -1) return; - LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(item->getAssetUUID()); - - avatar->userSetOptionalTE( hit_face, image); -} -*/ void LLToolDragAndDrop::dropTexture(LLViewerObject* hit_obj, S32 hit_face, LLInventoryItem* item, ESource source, const LLUUID& src_id, bool all_faces, + bool remove_pbr, S32 tex_channel) { LLSelectNode* nodep = nullptr; @@ -1295,13 +1364,15 @@ void LLToolDragAndDrop::dropTexture(LLViewerObject* hit_obj, if (all_faces) { - dropTextureAllFaces(hit_obj, item, source, src_id); + dropTextureAllFaces(hit_obj, item, source, src_id, remove_pbr); // If user dropped a texture onto face it implies // applying texture now without cancel, save to selection if (nodep) { uuid_vec_t texture_ids; + uuid_vec_t material_ids; + gltf_materials_vec_t override_materials; S32 num_faces = hit_obj->getNumTEs(); for (S32 face = 0; face < num_faces; face++) { @@ -1314,21 +1385,46 @@ void LLToolDragAndDrop::dropTexture(LLViewerObject* hit_obj, { texture_ids.push_back(LLUUID::null); } + + // either removed or modified materials + if (remove_pbr) + { + material_ids.push_back(LLUUID::null); + } + else + { + material_ids.push_back(hit_obj->getRenderMaterialID(face)); + } + + LLTextureEntry* te = hit_obj->getTE(hit_face); + if (te && !remove_pbr) + { + override_materials.push_back(te->getGLTFMaterialOverride()); + } + else + { + override_materials.push_back(nullptr); + } } + nodep->saveTextures(texture_ids); + nodep->saveGLTFMaterials(material_ids, override_materials); } } else { - dropTextureOneFace(hit_obj, hit_face, item, source, src_id); + dropTextureOneFace(hit_obj, hit_face, item, source, src_id, remove_pbr, tex_channel); // If user dropped a texture onto face it implies // applying texture now without cancel, save to selection - LLPanelFace* panel_face = gFloaterTools->getPanelFace(); + // LLPanelFace* panel_face = gFloaterTools->getPanelFace(); // switchable edit texture/materials panel if (nodep && gFloaterTools->getVisible() - && panel_face - && panel_face->getTextureDropChannel() == 0 /*texture*/ + // switchable edit texture/materials panel + // && panel_face + // && panel_face->getTextureDropChannel() == 0 /*texture*/ + && gFloaterTools->getTextureDropChannel() == 0 /*texture*/ + // && nodep->mSavedTextures.size() > hit_face) { LLViewerTexture* tex = hit_obj->getTEImage(hit_face); @@ -1340,6 +1436,16 @@ void LLToolDragAndDrop::dropTexture(LLViewerObject* hit_obj, { nodep->mSavedTextures[hit_face] = LLUUID::null; } + + LLTextureEntry* te = hit_obj->getTE(hit_face); + if (te && !remove_pbr) + { + nodep->mSavedGLTFOverrideMaterials[hit_face] = te->getGLTFMaterialOverride(); + } + else + { + nodep->mSavedGLTFOverrideMaterials[hit_face] = nullptr; + } } } } @@ -1349,6 +1455,7 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, LLInventoryItem* item, LLToolDragAndDrop::ESource source, const LLUUID& src_id, + bool remove_pbr, S32 tex_channel) { if (hit_face == -1) return; @@ -1357,27 +1464,67 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, LL_WARNS() << "LLToolDragAndDrop::dropTextureOneFace no texture item." << LL_ENDL; return; } - if (hit_obj->getRenderMaterialID(hit_face).notNull()) + + LLUUID asset_id = item->getAssetUUID(); + + if (hit_obj->getRenderMaterialID(hit_face).notNull() && !remove_pbr && tex_channel >= -1) // tex_channel -2 means ignorePBR then treat as -1, don't judge me. { + // Overrides require textures to be copy and transfer free + LLPermissions item_permissions = item->getPermissions(); + bool allow_adding_to_override = item_permissions.allowOperationBy(PERM_COPY, gAgent.getID()); + allow_adding_to_override &= item_permissions.allowOperationBy(PERM_TRANSFER, gAgent.getID()); + + if (allow_adding_to_override) + { + LLGLTFMaterial::TextureInfo drop_channel = LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR; + // switchable edit texture/materials panel + // LLPanelFace* panel_face = gFloaterTools->getPanelFace(); + // if (gFloaterTools->getVisible() && panel_face) + // { + // drop_channel = panel_face->getPBRDropChannel(); + // } + if (gFloaterTools->getVisible()) + { + drop_channel = gFloaterTools->getPBRDropChannel(); + } + // + set_texture_to_material(hit_obj, hit_face, asset_id, drop_channel); + LLGLTFMaterialList::flushUpdates(nullptr); + } return; } - LLUUID asset_id = item->getAssetUUID(); + // tex_channel -2 means ignorePBR then treat as -1 + if(tex_channel < -1) + { + tex_channel = -1; + } + // BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id); if (!success) { return; } + if (remove_pbr) + { + hit_obj->setRenderMaterialID(hit_face, LLUUID::null); + } + // update viewer side image in anticipation of update from simulator LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(asset_id); add(LLStatViewer::EDIT_TEXTURE, 1); - LLTextureEntry* tep = hit_obj ? (hit_obj->getTE(hit_face)) : NULL; + LLTextureEntry* tep = hit_obj->getTE(hit_face); - LLPanelFace* panel_face = gFloaterTools->getPanelFace(); + // switchable edit texture/materials panel + // LLPanelFace* panel_face = gFloaterTools->getPanelFace(); - if (gFloaterTools->getVisible() && panel_face) + // if (gFloaterTools->getVisible() && panel_face) + if (gFloaterTools->getVisible()) + // { - tex_channel = (tex_channel > -1) ? tex_channel : panel_face->getTextureDropChannel(); + // switchable edit texture/materials panel + // tex_channel = (tex_channel > -1) ? tex_channel : panel_face->getTextureDropChannel(); + tex_channel = (tex_channel > -1) ? tex_channel : gFloaterTools->getTextureDropChannel(); switch (tex_channel) { @@ -1389,9 +1536,12 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, break; case 1: + if (tep) { LLMaterialPtr old_mat = tep->getMaterialParams(); - LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat); + // switchable edit texture/materials panel + // LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat); + LLMaterialPtr new_mat = gFloaterTools->createDefaultMaterial(old_mat); new_mat->setNormalID(asset_id); tep->setMaterialParams(new_mat); hit_obj->setTENormalMap(hit_face, asset_id); @@ -1400,9 +1550,12 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, break; case 2: + if (tep) { LLMaterialPtr old_mat = tep->getMaterialParams(); - LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat); + // switchable edit texture/materials panel + // LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat); + LLMaterialPtr new_mat = gFloaterTools->createDefaultMaterial(old_mat); new_mat->setSpecularID(asset_id); tep->setMaterialParams(new_mat); hit_obj->setTESpecularMap(hit_face, asset_id); @@ -2284,6 +2437,7 @@ EAcceptance LLToolDragAndDrop::dad3dApplyToObject( LLViewerInventoryCategory* cat; locateInventory(item, cat); if (!item || !item->isFinished()) return ACCEPT_NO; + LLPermissions item_permissions = item->getPermissions(); EAcceptance rv = willObjectAcceptInventory(obj, item); if((mask & MASK_CONTROL)) { @@ -2298,12 +2452,12 @@ EAcceptance LLToolDragAndDrop::dad3dApplyToObject( return ACCEPT_NO_LOCKED; } - if (cargo_type == DAD_TEXTURE) + if (cargo_type == DAD_TEXTURE && (mask & MASK_ALT) == 0) { + bool has_non_pbr_faces = false; if ((mask & MASK_SHIFT)) { S32 num_faces = obj->getNumTEs(); - bool has_non_pbr_faces = false; for (S32 face = 0; face < num_faces; face++) { if (obj->getRenderMaterialID(face).isNull()) @@ -2312,14 +2466,19 @@ EAcceptance LLToolDragAndDrop::dad3dApplyToObject( break; } } - if (!has_non_pbr_faces) - { - return ACCEPT_NO; - } } - else if (obj->getRenderMaterialID(face).notNull()) + else { - return ACCEPT_NO; + has_non_pbr_faces = obj->getRenderMaterialID(face).isNull(); + } + + if (!has_non_pbr_faces) + { + // Only pbr faces selected, texture will be added to an override + // Overrides require textures to be copy and transfer free + bool allow_adding_to_override = item_permissions.allowOperationBy(PERM_COPY, gAgent.getID()); + allow_adding_to_override &= item_permissions.allowOperationBy(PERM_TRANSFER, gAgent.getID()); + if (!allow_adding_to_override) return ACCEPT_NO; } } @@ -2328,15 +2487,16 @@ EAcceptance LLToolDragAndDrop::dad3dApplyToObject( if (cargo_type == DAD_TEXTURE) { bool all_faces = mask & MASK_SHIFT; - if (item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + bool remove_pbr = mask & MASK_ALT; + if (item_permissions.allowOperationBy(PERM_COPY, gAgent.getID())) { - dropTexture(obj, face, item, mSource, mSourceID, all_faces); + dropTexture(obj, face, item, mSource, mSourceID, all_faces, remove_pbr); } else { ESource source = mSource; LLUUID source_id = mSourceID; - LLNotificationsUtil::add("ApplyInventoryToObject", LLSD(), LLSD(), [obj, face, item, source, source_id, all_faces](const LLSD& notification, const LLSD& response) + LLNotificationsUtil::add("ApplyInventoryToObject", LLSD(), LLSD(), [obj, face, item, source, source_id, all_faces, remove_pbr](const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); // if Cancel pressed @@ -2344,7 +2504,7 @@ EAcceptance LLToolDragAndDrop::dad3dApplyToObject( { return; } - dropTexture(obj, face, item, source, source_id, all_faces); + dropTexture(obj, face, item, source, source_id, all_faces, remove_pbr); }); } } @@ -2411,23 +2571,6 @@ EAcceptance LLToolDragAndDrop::dad3dMeshObject( return dad3dApplyToObject(obj, face, mask, drop, DAD_MESH); } - -/* -EAcceptance LLToolDragAndDrop::dad3dTextureSelf( - LLViewerObject* obj, S32 face, MASK mask, BOOL drop) -{ - LL_DEBUGS() << "LLToolDragAndDrop::dad3dTextureAvatar()" << LL_ENDL; - if(drop) - { - if( !(mask & MASK_SHIFT) ) - { - dropTextureOneFaceAvatar( (LLVOAvatar*)obj, face, (LLInventoryItem*)mCargoData); - } - } - return (mask & MASK_SHIFT) ? ACCEPT_NO : ACCEPT_YES_SINGLE; -} -*/ - EAcceptance LLToolDragAndDrop::dad3dWearItem( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index f69774952c..60a2f01107 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -249,17 +249,20 @@ public: ESource source, const LLUUID& src_id, bool all_faces, + bool replace_pbr, S32 tex_channel = -1); static void dropTextureOneFace(LLViewerObject* hit_obj, S32 hit_face, LLInventoryItem* item, ESource source, const LLUUID& src_id, + bool remove_pbr, S32 tex_channel = -1); static void dropTextureAllFaces(LLViewerObject* hit_obj, LLInventoryItem* item, ESource source, - const LLUUID& src_id); + const LLUUID& src_id, + bool remove_pbr); static void dropMaterial(LLViewerObject* hit_obj, S32 hit_face, LLInventoryItem* item, diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp index 0fa7c6c3a0..66588d2d5a 100644 --- a/indra/newview/lltoolface.cpp +++ b/indra/newview/lltoolface.cpp @@ -43,8 +43,8 @@ #include "rlvactions.h" // [/RLVa:KB] +// #include "llpanelface.h" // switchable edit texture/materials panel - include not needed // Add control to drag texture faces around -#include "llpanelface.h" #include "llspinctrl.h" #include "llkeyboard.h" #include "llwindow.h" @@ -290,11 +290,14 @@ void LLToolFace::render() LLFloaterTools* toolsFloater=(LLFloaterTools*) LLFloaterReg::findInstance("build"); if(toolsFloater) { - LLPanelFace* panelFace=toolsFloater->mPanelFace; - if(panelFace) - { - panelFace->refresh(); - } + // switchable edit texture/materials panel + // LLPanelFace* panelFace=toolsFloater->mPanelFace; + // if(panelFace) + // { + // panelFace->refresh(); + // } + toolsFloater->refreshPanelFace(); + // } #ifdef TEXTURE_GRAB_UPDATE_REGULARLY diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index 8966e851c6..9b8db4a7d6 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -254,7 +254,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s try { - res = this->parseResponse(httpResults, parseResult, body, translation, detected_lang, err_msg); + res = parseResponse(httpResults, parseResult, body, translation, detected_lang, err_msg); } catch (std::out_of_range&) { @@ -294,8 +294,6 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s if (!failure.empty()) failure(status, err_msg); } - - } //========================================================================= @@ -354,7 +352,6 @@ private: std::string& translation, std::string& detected_lang); static std::string getAPIKey(); - }; //------------------------------------------------------------------------- @@ -392,36 +389,37 @@ bool LLGoogleTranslationHandler::checkVerificationResponse( // virtual bool LLGoogleTranslationHandler::parseResponse( - const LLSD& http_response, + const LLSD& http_response, int& status, const std::string& body, std::string& translation, std::string& detected_lang, std::string& err_msg) const { + const std::string& text = !body.empty() ? body : http_response["error_body"].asStringRef(); + Json::Value root; Json::Reader reader; - if (!reader.parse(body, root)) + if (reader.parse(text, root)) { + if (root.isObject()) + { + // Request succeeded, extract translation from the XML body. + if (parseTranslation(root, translation, detected_lang)) + return true; + + // Request failed. Extract error message from the XML body. + parseErrorResponse(root, status, err_msg); + } + } + else + { + // XML parsing failed. Extract error message from the XML parser. err_msg = reader.getFormatedErrorMessages(); - return false; } - if (!root.isObject()) // empty response? should not happen - { - return false; - } - - if (status != HTTP_OK) - { - // Request failed. Extract error message from the response. - parseErrorResponse(root, status, err_msg); - return false; - } - - // Request succeeded, extract translation from the response. - return parseTranslation(root, translation, detected_lang); + return false; } // virtual @@ -494,7 +492,7 @@ void LLGoogleTranslationHandler::verifyKey(const LLSD &key, LLTranslate::KeyVeri /*virtual*/ void LLGoogleTranslationHandler::initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const { - headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); + headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_JSON); headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); } @@ -504,8 +502,7 @@ void LLGoogleTranslationHandler::initHttpHeader( const std::string& user_agent, const LLSD &key) const { - headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); - headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); + initHttpHeader(headers, user_agent); } LLSD LLGoogleTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, @@ -729,7 +726,7 @@ bool LLAzureTranslationHandler::parseResponse( return false; } - translation = first["text"].asString(); + translation = LLURI::unescape(first["text"].asString()); return true; } @@ -829,8 +826,13 @@ LLSD LLAzureTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCorout { LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray); LLCore::BufferArrayStream outs(rawbody.get()); + + static const std::string allowed_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz " + "0123456789" + "-._~"; + outs << "[{\"text\":\""; - outs << msg; + outs << LLURI::escape(msg, allowed_chars); outs << "\"}]"; return adapter->postRawAndSuspend(request, url, rawbody, options, headers); @@ -1315,5 +1317,4 @@ LLTranslationAPIHandler& LLTranslate::getHandler(EService service) } return azure; - } diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index 492e6579e9..97dc513583 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -140,6 +140,11 @@ bool LLURLDispatcherImpl::dispatch(const LLSLURL& slurl, LLMediaCtrl* web, bool trusted_browser) { + // SL-20422 : Clicking the "Bring it back" link on Aditi displays a teleport alert + // Stop further processing empty urls like [secondlife:/// Bring it back.] + if (slurl.getType() == LLSLURL::EMPTY) + return true; + const bool right_click = false; return dispatchCore(slurl, nav_type, right_click, web, trusted_browser); } diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 3e4accb2aa..87c1faee1e 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -988,9 +988,9 @@ void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCorouti // // FIRE-22943: Don't switch away from the "Recent Items" tab. - //LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, serverInventoryItem, FALSE, TAKE_FOCUS_NO, (panel == NULL)); - BOOL show_main_panel = (!panel || panel->getName() != "Recent Items"); - LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, serverInventoryItem, show_main_panel, TAKE_FOCUS_NO, (panel == NULL)); + //LLInventoryPanel::openInventoryPanelAndSetSelection(true, serverInventoryItem, false, false, !panel); + bool show_main_panel = (!panel || panel->getName() != "Recent Items"); + LLInventoryPanel::openInventoryPanelAndSetSelection(true, serverInventoryItem, show_main_panel, false, !panel); // // restore keyboard focus diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 0c0d9114f3..6d635b872c 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -846,8 +846,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 2") if (gResizeScreenTexture) { - gResizeScreenTexture = FALSE; gPipeline.resizeScreenTexture(); + gResizeScreenTexture = FALSE; } gGL.setColorMask(true, true); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 88d1870051..e8c46b6c13 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -352,9 +352,11 @@ void handle_disconnect_viewer(void *); void force_error_breakpoint(void *); void force_error_llerror(void *); +void force_error_llerror_msg(void*); void force_error_bad_memory_access(void *); void force_error_infinite_loop(void *); void force_error_software_exception(void *); +void force_error_os_exception(void*); void force_error_driver_crash(void *); void force_error_coroutine_crash(void *); void force_error_thread_crash(void *); @@ -2719,6 +2721,15 @@ class LLAdvancedForceErrorLlerror : public view_listener_t } }; +class LLAdvancedForceErrorLlerrorMsg: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_llerror_msg(NULL); + return true; + } +}; + class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -2762,6 +2773,15 @@ class LLAdvancedForceErrorSoftwareException : public view_listener_t } }; +class LLAdvancedForceOSException: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_os_exception(NULL); + return true; + } +}; + class LLAdvancedForceErrorSoftwareExceptionCoro : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -3915,6 +3935,15 @@ bool enable_object_select_in_pathfinding_characters() return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetViewableCharacters(); } +bool enable_os_exception() +{ +#if LL_DARWIN + return true; +#else + return false; +#endif +} + class LLSelfRemoveAllAttachments : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -7476,8 +7505,9 @@ void toggle_debug_menus(void*) // bool handleEvent(const LLSD& userdata) // { // LLFloaterIMContainer* im_box = LLFloaterIMContainer::getInstance(); -// bool nearby_visible = LLFloaterReg::getTypedInstance("nearby_chat")->isInVisibleChain(); -// if(nearby_visible && im_box->getSelectedSession() == LLUUID() && im_box->getConversationListItemSize() > 1) +// LLFloaterIMNearbyChat* floater_nearby = LLFloaterReg::getTypedInstance("nearby_chat"); +// if (floater_nearby->isInVisibleChain() && !floater_nearby->isTornOff() +// && im_box->getSelectedSession() == LLUUID() && im_box->getConversationListItemSize() > 1) // { // im_box->selectNextorPreviousConversation(false); // } @@ -10732,6 +10762,11 @@ void force_error_llerror(void *) LLAppViewer::instance()->forceErrorLLError(); } +void force_error_llerror_msg(void*) +{ + LLAppViewer::instance()->forceErrorLLErrorMsg(); +} + void force_error_bad_memory_access(void *) { LLAppViewer::instance()->forceErrorBadMemoryAccess(); @@ -10747,6 +10782,11 @@ void force_error_software_exception(void *) LLAppViewer::instance()->forceErrorSoftwareException(); } +void force_error_os_exception(void*) +{ + LLAppViewer::instance()->forceErrorOSSpecificException(); +} + void force_error_driver_crash(void *) { LLAppViewer::instance()->forceErrorDriverCrash(); @@ -12417,10 +12457,12 @@ void initialize_menus() // Advanced > Debugging view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint"); view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror"); + view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg"); view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess"); view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro"); view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); + view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException"); view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro"); view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); // Wrongly merged back in by LL @@ -12652,6 +12694,7 @@ void initialize_menus() enable.add("VisibleSelectInPathfindingLinksets", boost::bind(&visible_object_select_in_pathfinding_linksets)); commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters)); + enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception)); enable.add("EnableBridgeFunction", boost::bind(&enable_bridge_function)); // view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 949d759b5e..c112f79445 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1726,20 +1726,29 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam } else { - // Highlight item - // Only show if either ShowInInventory is true OR it is an inventory - // offer from an agent and the asset is not previewable - const BOOL auto_open = gSavedSettings.getBOOL("ShowInInventory") || (from_agent_manual && !check_asset_previewable(asset_type)); - //gSavedSettings.getBOOL("ShowInInventory") && // don't open if showininventory is false - //!from_name.empty(); // don't open if it's not from anyone. - // Use correct inventory floater - //if (auto_open) - //{ - // LLFloaterReg::showInstance("inventory"); - //} - // - if (auto_open) // Don't mess with open inventory panels when ShowInInventory is FALSE - LLInventoryPanel::openInventoryPanelAndSetSelection(auto_open, obj_id, true); + // Highlight item + // Only show if either ShowInInventory is true OR it is an inventory + // offer from an agent and the asset is not previewable + //bool show_in_inventory = gSavedSettings.get("ShowInInventory"); + //bool auto_open = + // show_in_inventory && // don't open if ShowInInventory is FALSE + // !from_name.empty(); // don't open if it's not from anyone + + //// SL-20419 : Don't change active tab if floater is visible + //LLFloater* instance = LLFloaterReg::findInstance("inventory"); + //bool use_main_panel = instance && instance->getVisible(); + + //if (auto_open) + //{ + // LLFloaterReg::showInstance("inventory"); + //} + + //LLInventoryPanel::openInventoryPanelAndSetSelection(auto_open, obj_id, use_main_panel); + + const bool auto_open = gSavedSettings.getBOOL("ShowInInventory") || (from_agent_manual && !check_asset_previewable(asset_type)); + if (auto_open) // Don't mess with open inventory panels when ShowInInventory is FALSE + LLInventoryPanel::openInventoryPanelAndSetSelection(auto_open, obj_id, true); + // } } } @@ -5362,7 +5371,7 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) LLObjectSignaledAnimationMap::instance().getMap()[uuid] = signaled_anims; LLViewerObject *objp = gObjectList.findObject(uuid); - if (!objp) + if (!objp || objp->isDead()) { LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for unknown object " << uuid << LL_ENDL; return; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 58a907cdc1..d29029a89a 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -410,6 +410,13 @@ LLViewerObject::~LLViewerObject() sNumObjects--; sNumZombieObjects--; llassert(mChildList.size() == 0); + llassert(mControlAvatar.isNull()); // Should have been cleaned by now + if (mControlAvatar.notNull()) + { + mControlAvatar->markForDeath(); + mControlAvatar = NULL; + LL_WARNS() << "Dead object owned a live control avatar" << LL_ENDL; + } clearInventoryListeners(); } @@ -3226,6 +3233,10 @@ void LLViewerObject::updateControlAvatar() return; } + // caller isn't supposed to operate on a dead object, + // avatar was already cleaned up + llassert(!isDead()); + bool should_have_control_avatar = false; if (is_animated_object) { @@ -3322,7 +3333,6 @@ void LLViewerObject::unlinkControlAvatar() if (mControlAvatar) { mControlAvatar->markForDeath(); - mControlAvatar->mRootVolp = NULL; mControlAvatar = NULL; } } @@ -5220,11 +5230,6 @@ void LLViewerObject::updateTEMaterialTextures(U8 te) LLViewerObject* obj = gObjectList.findObject(id); if (obj) { - LLViewerRegion* region = obj->getRegion(); - if(region) - { - region->loadCacheMiscExtras(obj->getLocalID()); - } obj->markForUpdate(); } }); @@ -5303,7 +5308,7 @@ void LLViewerObject::setTEImage(const U8 te, LLViewerTexture *imagep) S32 LLViewerObject::setTETextureCore(const U8 te, LLViewerTexture *image) { LLUUID old_image_id = getTEref(te).getID(); - const LLUUID& uuid = image->getID(); + const LLUUID& uuid = image ? image->getID() : LLUUID::null; S32 retval = 0; if (uuid != getTEref(te).getID() || uuid == LLUUID::null) diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index a4eb418274..7a467720b5 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -83,7 +83,6 @@ #include "llcorehttputil.h" #include "llcallstack.h" #include "llsettingsdaycycle.h" - #include // Firestorm includes @@ -845,8 +844,13 @@ void LLViewerRegion::loadObjectCache() if(LLVOCache::instanceExists()) { LLVOCache & vocache = LLVOCache::instance(); - vocache.readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap); - vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesLLSD); + // FIRE-33808 - Material Override Cache causes long delays + // vocache.readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap); + // vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesLLSD); + // mark as dirty if read fails to force a rewrite. + mCacheDirty = !vocache.readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap); + vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesLLSD, mImpl->mCacheMap); + // if (mImpl->mCacheMap.empty()) { @@ -880,10 +884,17 @@ void LLViewerRegion::saveObjectCache() mCacheDirty = FALSE; } - // Map of LLVOCacheEntry takes time to release, store map for cleanup on idle - sRegionCacheCleanup.insert(mImpl->mCacheMap.begin(), mImpl->mCacheMap.end()); - mImpl->mCacheMap.clear(); - // TODO - probably need to do the same for overrides cache + if (LLAppViewer::instance()->isQuitting()) + { + mImpl->mCacheMap.clear(); + } + else + { + // Map of LLVOCacheEntry takes time to release, store map for cleanup on idle + sRegionCacheCleanup.insert(mImpl->mCacheMap.begin(), mImpl->mCacheMap.end()); + mImpl->mCacheMap.clear(); + // TODO - probably need to do the same for overrides cache + } } void LLViewerRegion::sendMessage() @@ -1241,12 +1252,16 @@ void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry, bool for_rendering) } } + // Fix the missing kill on overrides + mImpl->mGLTFOverridesLLSD.erase(entry->getLocalID()); + // //will remove it from the object cache, real deletion entry->setState(LLVOCacheEntry::INACTIVE); entry->removeOctreeEntry(); entry->setValid(FALSE); - - // TODO kill extras/material overrides cache too + // Fix the missing kill on overrides + // // TODO kill extras/material overrides cache too + } //physically delete the cache entry @@ -1965,8 +1980,6 @@ LLViewerObject* LLViewerRegion::addNewObject(LLVOCacheEntry* entry) addActiveCacheEntry(entry); } - loadCacheMiscExtras(entry->getLocalID()); - return obj; } @@ -2680,7 +2693,10 @@ void LLViewerRegion::decodeBoundingInfo(LLVOCacheEntry* entry) //set parent id U32 parent_id = 0; - LLViewerObject::unpackParentID(entry->getDP(), parent_id); + if (entry->getDP()) // NULL if nothing cached + { + LLViewerObject::unpackParentID(entry->getDP(), parent_id); + } if(parent_id != entry->getParentID()) { entry->setParentID(parent_id); @@ -2700,7 +2716,7 @@ void LLViewerRegion::decodeBoundingInfo(LLVOCacheEntry* entry) LLQuaternion rot; //decode spatial info and parent info - U32 parent_id = LLViewerObject::extractSpatialExtents(entry->getDP(), pos, scale, rot); + U32 parent_id = entry->getDP() ? LLViewerObject::extractSpatialExtents(entry->getDP(), pos, scale, rot) : entry->getParentID(); U32 old_parent_id = entry->getParentID(); bool same_old_parent = false; @@ -3926,15 +3942,6 @@ std::string LLViewerRegion::getSimHostName() return std::string("..."); } -void LLViewerRegion::loadCacheMiscExtras(U32 local_id) -{ - auto iter = mImpl->mGLTFOverridesLLSD.find(local_id); - if (iter != mImpl->mGLTFOverridesLLSD.end()) - { - LLGLTFMaterialList::loadCacheOverrides(iter->second); - } -} - void LLViewerRegion::applyCacheMiscExtras(LLViewerObject* obj) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; @@ -3944,6 +3951,12 @@ void LLViewerRegion::applyCacheMiscExtras(LLViewerObject* obj) auto iter = mImpl->mGLTFOverridesLLSD.find(local_id); if (iter != mImpl->mGLTFOverridesLLSD.end()) { + // backfill the UUID if it was left empty + if (iter->second.mObjectId.isNull()) + { + iter->second.mObjectId = obj->getID(); + } + // llassert(iter->second.mGLTFMaterial.size() == iter->second.mSides.size()); for (auto& side : iter->second.mGLTFMaterial) diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 5713a606e3..f0878b65cb 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -465,8 +465,6 @@ private: bool isNonCacheableObjectCreated(U32 local_id); public: - void loadCacheMiscExtras(U32 local_id); - void applyCacheMiscExtras(LLViewerObject* obj); struct CompareDistance diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index beca344d17..e4f65b6a67 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -3605,7 +3605,10 @@ void LLViewerMediaTexture::addFace(U32 ch, LLFace* facep) if(te && te->getID().notNull()) //should have a texture { - LL_ERRS() << "The face does not have a valid texture before media texture." << LL_ENDL; + LL_WARNS_ONCE() << "The face's texture " << te->getID() << " is not valid. Face must have a valid texture before media texture." << LL_ENDL; + // This might break the object, but it likely isn't a 'recoverable' situation. + LLViewerFetchedTexture* tex = LLViewerTextureManager::getFetchedTexture(te->getID()); + mTextureList.push_back(tex); } } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 3a87e19470..c8db0876a0 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -124,8 +124,17 @@ void LLViewerTextureList::doPreloadImages() LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName(); LLUIImageList* image_list = LLUIImageList::getInstance(); - // Set the default flat normal map - LLViewerFetchedTexture::sFlatNormalImagep = LLViewerTextureManager::getFetchedTextureFromFile("flatnormal.tga", FTT_LOCAL_FILE, MIPMAP_NO, LLViewerFetchedTexture::BOOST_BUMP); + // Set the default flat normal map + // BLANK_OBJECT_NORMAL has a version on dataserver, but it has compression artifacts + LLViewerFetchedTexture::sFlatNormalImagep = + LLViewerTextureManager::getFetchedTextureFromFile("flatnormal.tga", + FTT_LOCAL_FILE, + MIPMAP_NO, + LLViewerFetchedTexture::BOOST_BUMP, + LLViewerTexture::FETCHED_TEXTURE, + 0, + 0, + BLANK_OBJECT_NORMAL); // PBR: irradiance LLViewerFetchedTexture::sDefaultIrradiancePBRp = LLViewerTextureManager::getFetchedTextureFromFile("default_irradiance.png", FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI); @@ -691,7 +700,6 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image) assert_main_thread(); llassert_always(mInitialized) ; llassert(image); - image->validateRefCount(); S32 count = 0; if (image->isInImageList()) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 7ef40dbe7f..e5f49879dd 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2067,7 +2067,11 @@ LLViewerWindow::LLViewerWindow(const Params& p) // Initialize OpenGL Renderer LLVertexBuffer::initClass(mWindow); LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ; - gGL.init(true); + if (!gGL.init(true)) + { + LLError::LLUserWarningMsg::show(LLTrans::getString("MBVideoDrvErr")); + LL_ERRS() << "gGL not initialized" << LL_ENDL; + } // Exodus vignette if (LLFeatureManager::getInstance()->isSafe() diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 253f77aa3d..c24d1532b0 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2733,7 +2733,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) { if (!mIsControlAvatar) { - idleUpdateNameTag( mLastRootPos ); + idleUpdateNameTag(idleCalcNameTagPosition(mLastRootPos)); } return; } @@ -2834,7 +2834,9 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) && LLVoiceClient::getInstance()->getVoiceEnabled(mID); - idleUpdateVoiceVisualizer( voice_enabled ); + LLVector3 hud_name_pos = idleCalcNameTagPosition(mLastRootPos); + + idleUpdateVoiceVisualizer(voice_enabled, hud_name_pos); idleUpdateMisc( detailed_update ); idleUpdateAppearanceAnimation(); if (detailed_update) @@ -2845,7 +2847,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) idleUpdateWindEffect(); } - idleUpdateNameTag( mLastRootPos ); + idleUpdateNameTag(hud_name_pos); // Complexity has stale mechanics, but updates still can be very rapid // so spread avatar complexity calculations over frames to lesen load from @@ -2885,7 +2887,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) idleUpdateDebugInfo(); } -void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) +void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled, const LLVector3 &position) { bool render_visualizer = voice_enabled; @@ -2987,24 +2989,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) } } } - - //-------------------------------------------------------------------------------------------- - // here we get the approximate head position and set as sound source for the voice symbol - // (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing) - //-------------------------------------------------------------------------------------------- - - if ( isSitting() ) - { - LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] ); - mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot->getWorldPosition() + headOffset ); - } - else - { - LLVector3 tagPos = mRoot->getWorldPosition(); - tagPos[VZ] -= mPelvisToFoot; - tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); // does not need mAvatarOffset -Nyx - mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos ); - } + mVoiceVisualizer->setPositionAgent(position); }//if ( voiceEnabled ) } @@ -3585,7 +3570,8 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) new_name = TRUE; } - idleUpdateNameTagPosition(root_pos_last); + mNameText->setPositionAgent(root_pos_last); + idleUpdateNameTagText(new_name); // Wolfspirit: Following thing is already handled in LLHUDNameTag::lineSegmentIntersect // Fixing bubblechat alpha flashing with commenting this out. @@ -4145,7 +4131,7 @@ void LLVOAvatar::invalidateNameTags() } // Compute name tag position during idle update -void LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last) +LLVector3 LLVOAvatar::idleCalcNameTagPosition(const LLVector3 &root_pos_last) { LLQuaternion root_rot = mRoot->getWorldRotation(); LLQuaternion inv_root_rot = ~root_rot; @@ -4207,7 +4193,26 @@ void LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last) name_position[VZ] += fsNameTagOffset / 10.f; // - mNameText->setPositionAgent(name_position); + const F32 water_height = getRegion()->getWaterHeight(); + static const F32 WATER_HEIGHT_DELTA = 0.25f; + if (name_position[VZ] < water_height + WATER_HEIGHT_DELTA) + { + if (LLViewerCamera::getInstance()->getOrigin()[VZ] >= water_height) + { + name_position[VZ] = water_height; + } + else if (mNameText) // both camera and HUD are below watermark + { + F32 name_world_height = mNameText->getWorldHeight(); + F32 max_z_position = water_height - name_world_height; + if (name_position[VZ] > max_z_position) + { + name_position[VZ] = max_z_position; + } + } + } + + return name_position; } void LLVOAvatar::idleUpdateNameTagAlpha(bool new_name, F32 alpha) @@ -4330,6 +4335,10 @@ bool LLVOAvatar::isVisuallyMuted() // muted = true; //} // + else if (mIsControlAvatar) + { + muted = isTooSlow(); + } else { muted = isTooComplex(); // this should not trigger based on perfstats diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index f8a1e788d5..e05c196785 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -284,7 +284,7 @@ public: void updateTimeStep(); void updateRootPositionAndRotation(LLAgent &agent, F32 speed, bool was_sit_ground_constrained); - void idleUpdateVoiceVisualizer(bool voice_enabled); + void idleUpdateVoiceVisualizer(bool voice_enabled, const LLVector3 &position); void idleUpdateMisc(bool detailed_update); virtual void idleUpdateAppearanceAnimation(); void idleUpdateLipSync(bool voice_enabled); @@ -292,7 +292,6 @@ public: void idleUpdateWindEffect(); void idleUpdateNameTag(const LLVector3& root_pos_last); void idleUpdateNameTagText(bool new_name); - void idleUpdateNameTagPosition(const LLVector3& root_pos_last); void idleUpdateNameTagAlpha(bool new_name, F32 alpha); // Colorize tags //LLColor4 getNameTagColor(bool is_friend); @@ -361,6 +360,8 @@ public: static void updateNearbyAvatarCount(); + LLVector3 idleCalcNameTagPosition(const LLVector3 &root_pos_last); + //-------------------------------------------------------------------- // Static preferences (controlled by user settings/menus) //-------------------------------------------------------------------- diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 5bf990c806..bfcae9d3b4 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -34,6 +34,7 @@ #include "llagentcamera.h" #include "llsdserialize.h" #include "llagent.h" // For gAgent +#include "llworld.h" // For LLWorld::getInstance() //static variables U32 LLVOCacheEntry::sMinFrameRange = 0; @@ -55,6 +56,10 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes) { return apr_file->write(src, n_bytes) == n_bytes ; } +// FIRE-33808 - Material Override Cache causes long delays +const std::string LLGLTFOverrideCacheEntry::VERSION_LABEL = {"GLTFCacheVer"}; +const int LLGLTFOverrideCacheEntry::VERSION = 1; +// bool LLGLTFOverrideCacheEntry::fromLLSD(const LLSD& data) { @@ -236,6 +241,8 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file) } else { + // improve logging around vocache + LL_WARNS() << "Error loading cache entry for " << mLocalID << ", size " << size << " aborting!" << LL_ENDL; delete[] mBuffer ; mBuffer = NULL ; } @@ -1289,6 +1296,11 @@ void LLVOCache::removeEntry(HeaderEntryInfo* entry) { return; } + // FIRE-33808 - Material Override Cache causes long delays + std::string filename; + getObjectCacheFilename(entry->mHandle, filename); + LL_INFOS() << "Removing entry for region with filename" << filename << LL_ENDL; + // header_entry_queue_t::iterator iter = mHeaderEntryQueue.find(entry); if(iter != mHeaderEntryQueue.end()) @@ -1359,6 +1371,11 @@ void LLVOCache::removeFromCache(HeaderEntryInfo* entry) std::string filename; getObjectCacheFilename(entry->mHandle, filename); LLAPRFile::remove(filename, mLocalAPRFilePoolp); + // FIRE-33808 - Material Override Cache causes long delays + // Note that removeFromCache should take responsibility for cleaning up all cache artefactgs specfic to the handle/entry. + // as such this now includes the generic extras + removeGenericExtrasForHandle(entry->mHandle); + // entry->mTime = INVALID_TIME ; updateEntry(entry) ; //update the head file. } @@ -1507,13 +1524,17 @@ BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry) return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; } - -void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) +// FIRE-33808 - Material Override Cache causes long delays +// void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) +// we now return bool to trigger dirty cache +// and force a rewrite after a partial read due to corruption. +bool LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) +// { if(!mEnabled) { LL_WARNS() << "Not reading cache for handle " << handle << "): Cache is currently disabled." << LL_ENDL; - return ; + return true; // FIRE-33808 - Material Override Cache causes long delays } llassert_always(mInitialized); @@ -1521,12 +1542,13 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca if(iter == mHandleEntryMap.end()) //no cache { LL_WARNS() << "No handle map entry for " << handle << LL_ENDL; - return ; + return false; // FIRE-33808 - Material Override Cache causes long delays } bool success = true ; + S32 num_entries=0; // FIRE-33808 - Material Override Cache causes long delays + std::string filename; { - std::string filename; LLUUID cache_id; getObjectCacheFilename(handle, filename); LLAPRFile apr_file(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp); @@ -1543,7 +1565,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca if(success) { - S32 num_entries; // if removal was enabled during write num_entries might be wrong + // S32 num_entries; // if removal was enabled during write num_entries might be wrong success = check_read(&apr_file, &num_entries, sizeof(S32)) ; if(success) @@ -1554,7 +1576,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca if (!entry->getLocalID()) { LL_WARNS() << "Aborting cache file load for " << filename << ", cache file corruption!" << LL_ENDL; - success = false ; + success = false ; break ; } cache_entry_map[entry->getLocalID()] = entry; @@ -1570,13 +1592,24 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca { removeEntry(iter->second) ; } - } - return ; + } + // FIRE-33808 - Material Override Cache causes long delays + // return ; + LL_DEBUGS("GLTF", "VOCache") << "Read " << cache_entry_map.size() << " entries from object cache " << filename << ", expected " << num_entries << ", success=" << (success?"True":"False") << LL_ENDL; + return success; + // } -void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map) +// FIRE-33808 - Material Override Cache causes long delays +// void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map) +void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) { + int loaded= 0; + int discarded = 0; + // get ViewerRegion pointer from handle + LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromHandle(handle); +// if(!mEnabled) { LL_WARNS() << "Not reading cache for handle " << handle << "): Cache is currently disabled." << LL_ENDL; @@ -1598,19 +1631,42 @@ void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCac std::getline(in, line); if(!in.good()) { LL_WARNS() << "Failed reading extras cache for handle " << handle << LL_ENDL; + // FIRE-33808 - Material Override Cache causes long delays + in.close(); + removeGenericExtrasForHandle(handle); + // return; } + // FIRE-33808 - Material Override Cache causes long delays + // file formats need versions, let's add one. legacy cache files will be considered version 0 + int versionNumber=0; + if (line.compare(0, LLGLTFOverrideCacheEntry::VERSION_LABEL.length(), LLGLTFOverrideCacheEntry::VERSION_LABEL) == 0) + { + std::string versionStr = line.substr(LLGLTFOverrideCacheEntry::VERSION_LABEL.length()+1); // skip the version label and ':' + versionNumber = std::stol(versionStr); + std::getline(in, line); // read the next line for the region UUID check + } + // if(!LLUUID::validate(line)) { LL_WARNS() << "Failed reading extras cache for handle" << handle << ". invalid uuid line: '" << line << "'" << LL_ENDL; + // FIRE-33808 - Material Override Cache causes long delays + in.close(); + removeGenericExtrasForHandle(handle); + // return; } LLUUID cache_id(line); if(cache_id != id) { - LL_INFOS() << "Cache ID doesn't match for this region, discarding" << LL_ENDL; + // FIRE-33808 - Material Override Cache causes long delays + // if the cache id doesn't match the expected region we should just kill the file. + LL_WARNS() << "Cache ID doesn't match for this region, deleting it" << LL_ENDL; + in.close(); + removeGenericExtrasForHandle(handle); + // return; } @@ -1618,6 +1674,10 @@ void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCac std::getline(in, line); if(!in.good()) { LL_WARNS() << "Failed reading extras cache for handle " << handle << LL_ENDL; + // FIRE-33808 - Material Override Cache causes long delays + in.close(); + removeGenericExtrasForHandle(handle); + // return; } try { @@ -1626,10 +1686,15 @@ void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCac catch(std::logic_error&) // either invalid_argument or out_of_range { LL_WARNS() << "Failed reading extras cache for handle " << handle << ". unreadable num_entries" << LL_ENDL; + // FIRE-33808 - Material Override Cache causes long delays + in.close(); + removeGenericExtrasForHandle(handle); + // return; } - LL_DEBUGS("GLTF") << "Beginning reading extras cache for handle " << handle << ", " << num_entries << " entries" << LL_ENDL; + // FIRE-33808 - Material Override Cache causes long delays + LL_DEBUGS("GLTF") << "Beginning reading extras cache for handle " << handle << " from " << getObjectCacheExtrasFilename(handle) << LL_ENDL; LLSD entry_llsd; for (U32 i = 0; i < num_entries && !in.eof(); i++) @@ -1638,46 +1703,77 @@ void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCac bool success = LLSDSerialize::deserialize(entry_llsd, in, max_size); // check bool(in) this time since eof is not a failure condition here if(!success || !in) { - LL_WARNS() << "Failed reading extras cache for handle " << handle << ", entry number " << i << LL_ENDL; - return; + // FIRE-33808 - Material Override Cache causes long delays + LL_WARNS() << "Failed reading extras cache for handle " << handle << ", entry number " << i << " cache patrtial load only." << LL_ENDL; + in.close(); + removeGenericExtrasForHandle(handle); + break; + // } LLGLTFOverrideCacheEntry entry; entry.fromLLSD(entry_llsd); U32 local_id = entry_llsd["local_id"].asInteger(); - cache_extras_entry_map[local_id] = entry; + // FIRE-33808 - Material Override Cache causes long delays + // cache_extras_entry_map[local_id] = entry; + // only add entries that exist in the primary cache + // this is a self-healing test that avoids us polluting the cache with entries that are no longer valid. + if(cache_entry_map.find(local_id)!= cache_entry_map.end()) + { + // attempt to backfill a null objectId, though these shouldn't be in the persisted cache really + if(entry.mObjectId.isNull() && pRegion) + { + gObjectList.getUUIDFromLocal( entry.mObjectId, local_id, pRegion->getHost().getAddress(), pRegion->getHost().getPort() ); + } + cache_extras_entry_map[local_id] = entry; + loaded++; + } + else + { + discarded++; + } } - - LL_DEBUGS("GLTF") << "Completed reading extras cache for handle " << handle << ", " << num_entries << " entries" << LL_ENDL; + LL_DEBUGS("GLTF") << "Completed reading extras cache for handle " << handle << ", " << loaded << " loaded, " << discarded << " discarded" << LL_ENDL; + // } void LLVOCache::purgeEntries(U32 size) { + // FIRE-33808 - Material Override Cache causes long delays + LL_DEBUGS("VOCache","GLTF") << "Purging " << size << " entries from cache" << LL_ENDL; while(mHeaderEntryQueue.size() > size) { header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; HeaderEntryInfo* entry = *iter ; mHandleEntryMap.erase(entry->mHandle); - mHeaderEntryQueue.erase(iter) ; - removeFromCache(entry) ; + // FIRE-33808 - Material Override Cache causes long delays + mHeaderEntryQueue.erase(iter); + removeFromCache(entry); + // delete entry; - // TODO also delete extras + } mNumEntries = mHandleEntryMap.size() ; } void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache, bool removal_enabled) { + // FIRE-33808 - Material Override Cache causes long delays + std::string filename; + getObjectCacheFilename(handle, filename); + // if(!mEnabled) { - LL_WARNS() << "Not writing cache for handle " << handle << "): Cache is currently disabled." << LL_ENDL; + // FIRE-33808 - Material Override Cache causes long delays + LL_WARNS() << "Not writing cache for " << filename << " (handle:" << handle << "): Cache is currently disabled." << LL_ENDL; return ; } llassert_always(mInitialized); if(mReadOnly) { - LL_WARNS() << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << LL_ENDL; + // FIRE-33808 - Material Override Cache causes long delays + LL_WARNS() << "Not writing cache for " << filename << " (handle:" << handle << "): Cache is currently in read-only mode." << LL_ENDL; return ; } @@ -1712,13 +1808,15 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: //update cache header if(!updateEntry(entry)) { - LL_WARNS() << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << LL_ENDL; + // FIRE-33808 - Material Override Cache causes long delays + LL_WARNS() << "Failed to update cache header index " << entry->mIndex << ". " << filename << " handle = " << handle << LL_ENDL; return ; //update failed. } if(!dirty_cache) { - LL_WARNS() << "Skipping write to cache for handle " << handle << ": cache not dirty" << LL_ENDL; + // FIRE-33808 - Material Override Cache causes long delays + LL_WARNS() << "Skipping write to cache for " << filename << " (handle:" << handle << "): cache not dirty" << LL_ENDL; return ; //nothing changed, no need to update. } @@ -1754,6 +1852,8 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: } else { + // FIRE-33808 - Material Override Cache causes long delays + LL_WARNS() << "Failed to write cache entry to buffer for " << filename << ", entry number " << iter->second->getLocalID() << LL_ENDL; success = false; break; } @@ -1765,6 +1865,8 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: size_in_buffer = 0; if (!success) { + // FIRE-33808 - Material Override Cache causes long delays + LL_WARNS() << "Failed to write cache to disk " << filename << LL_ENDL; break; } } @@ -1775,8 +1877,16 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: { // final write success = check_write(&apr_file, (void*)data_buffer, size_in_buffer); + // FIRE-33808 - Material Override Cache causes long delays + if(!success) + { + LL_WARNS() << "Failed to write cache entry to disk " << filename << LL_ENDL; + } + // size_in_buffer = 0; } + // FIRE-33808 - Material Override Cache causes long delays + LL_DEBUGS("VOCache") << "Wrote " << num_entries << " entries to the primary VOCache file " << filename << ". success = " << (success ? "True":"False") << LL_ENDL; } } } @@ -1788,6 +1898,18 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: return ; } +// FIRE-33808 - Material Override Cache causes long delays +void LLVOCache::removeGenericExtrasForHandle(U64 handle) +{ + if(mReadOnly) + { + LL_WARNS() << "Not removing cache for handle " << handle << ": Cache is currently in read-only mode." << LL_ENDL; + return ; + } + LL_WARNS("GLTF", "VOCache") << "Removing generic extras for handle " << handle << "Filename: " << getObjectCacheExtrasFilename(handle) << LL_ENDL; + LLFile::remove(getObjectCacheExtrasFilename(handle)); +} +// void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, BOOL dirty_cache, bool removal_enabled) { @@ -1804,46 +1926,106 @@ void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LL return; } - std::string filename(getObjectCacheExtrasFilename(handle)); + // FIRE-33808 - Material Override Cache causes long delays + std::string filename = getObjectCacheExtrasFilename(handle); + // llofstream out(filename, std::ios::out | std::ios::binary); if(!out.good()) { LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL; + // FIRE-33808 - Material Override Cache causes long delays + // return; + // // TODO - clean up broken cache file + // } + + // out << id << '\n'; + // if(!out.good()) + // { + // LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL; + // return; + // // TODO - clean up broken cache file + // } + + // U32 num_entries = cache_extras_entry_map.size(); + // out << num_entries << '\n'; + // if(!out.good()) + // { + // LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL; + // return; + // // TODO - clean up broken cache file + // } + removeGenericExtrasForHandle(handle); return; - // TODO - clean up broken cache file } + // It is good practice to version file formats so let's add one. + // legacy versions will be treated as version 0. + out << LLGLTFOverrideCacheEntry::VERSION_LABEL << ":" << LLGLTFOverrideCacheEntry::VERSION << '\n'; out << id << '\n'; if(!out.good()) { LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL; + removeGenericExtrasForHandle(handle); // FIRE-33808 - Material Override Cache causes long delays return; - // TODO - clean up broken cache file } - U32 num_entries = cache_extras_entry_map.size(); - out << num_entries << '\n'; + auto num_entries_placeholder = out.tellp(); + out << std::setw(10) << std::setfill('0') << 0 << '\n'; if(!out.good()) { LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL; + removeGenericExtrasForHandle(handle); return; - // TODO - clean up broken cache file } - for (auto const & entry : cache_extras_entry_map) + // get ViewerRegion pointer from handle + LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromHandle(handle); + + U32 num_entries = 0; + U32 inmem_entries = 0; + U32 skipped = 0; + inmem_entries = cache_extras_entry_map.size(); + for (auto [local_id, entry] : cache_extras_entry_map) { - S32 local_id = entry.first; - LLSD entry_llsd = entry.second.toLLSD(); - entry_llsd["local_id"] = local_id; - LLSDSerialize::serialize(entry_llsd, out, LLSDSerialize::LLSD_XML); - out << '\n'; - if(!out.good()) + // Only write out GLTFOverrides that we can actually apply again on import. + // worst case we have an extra cache miss. + // Note: mObjectId is valid in memory as we might have a data race between GLTF of the object itself. + // This remains a valid state to persist as it is consistent with the localid checks on import with the main cache. + if(entry.mObjectId.isNull() && pRegion) { - LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL; - return; - // TODO - clean up broken cache file + gObjectList.getUUIDFromLocal( entry.mObjectId, local_id, pRegion->getHost().getAddress(), pRegion->getHost().getPort() ); + } + + if( /*entry.mObjectId.notNull() &&*/ + entry.mSides.size() > 0 && + entry.mSides.size() == entry.mGLTFMaterial.size() + ) + { + LLSD entry_llsd = entry.toLLSD(); + entry_llsd["local_id"] = (S32)local_id; + LLSDSerialize::serialize(entry_llsd, out, LLSDSerialize::LLSD_XML); + out << '\n'; + if(!out.good()) + { + // We're not in a good place when this happens so we might as well nuke the file. + LL_WARNS() << "Failed writing extras cache for handle " << handle << ". Corrupted cache file " << filename << " removed." << LL_ENDL; + removeGenericExtrasForHandle(handle); + return; + } + num_entries++; + } + else + { + skipped++; } } - - LL_DEBUGS("GLTF") << "Completed writing extras cache for handle " << handle << ", " << num_entries << " entries" << LL_ENDL; + out.seekp(num_entries_placeholder); + out << std::setw(10) << std::setfill('0') << num_entries << '\n'; + if(!out.good()) + { + LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL; + removeGenericExtrasForHandle(handle); + return; + } + LL_DEBUGS("GLTF") << "Completed writing extras cache for handle " << handle << ", " << num_entries << " entries. Total in RAM: " << inmem_entries << " skipped (no persist): " << skipped << LL_ENDL; } diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 8525edd121..c4db69ed48 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -43,6 +43,8 @@ class LLCamera; class LLGLTFOverrideCacheEntry { public: + static const std::string VERSION_LABEL; + static const int VERSION; bool fromLLSD(const LLSD& data); LLSD toLLSD() const; @@ -95,12 +97,13 @@ public: } } }; - - struct ExtrasEntry - { - LLSD extras; - std::string extras_raw; - }; + // Unused, remove to reduce cognitive load + // struct ExtrasEntry + // { + // LLSD extras; + // std::string extras_raw; + // }; + // protected: ~LLVOCacheEntry(); @@ -288,13 +291,17 @@ public: // We need this init to be separate from constructor, since we might construct cache, purge it, then init. void initCache(ELLPath location, U32 size, U32 cache_version); void removeCache(ELLPath location, bool started = false) ; - - void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ; - void readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map); + // FIRE-33808 - Material Override Cache causes long delays + // void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ; + // void readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map); + bool readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ; + void readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map); + // void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache, bool removal_enabled); void writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, BOOL dirty_cache, bool removal_enabled); void removeEntry(U64 handle) ; + void removeGenericExtrasForHandle(U64 handle); // FIRE-33808 - Material Override Cache causes long delays U32 getCacheEntries() { return mNumEntries; } U32 getCacheEntriesMax() { return mCacheSize; } diff --git a/indra/newview/llvoicevisualizer.cpp b/indra/newview/llvoicevisualizer.cpp index ccbfe39328..122a2561cf 100644 --- a/indra/newview/llvoicevisualizer.cpp +++ b/indra/newview/llvoicevisualizer.cpp @@ -40,6 +40,7 @@ #include "llviewertexturelist.h" #include "llvoiceclient.h" #include "llrender.h" +#include "llagent.h" //brent's wave image //29de489d-0491-fb00-7dab-f9e686d31e83 @@ -349,7 +350,7 @@ void LLVoiceVisualizer::render() //--------------------------------------------------------------- // set the sound symbol position over the source (avatar's head) //--------------------------------------------------------------- - mSoundSymbol.mPosition = mVoiceSourceWorldPosition + WORLD_UPWARD_DIRECTION * HEIGHT_ABOVE_HEAD; + mSoundSymbol.mPosition = gAgent.getPosAgentFromGlobal(mPositionGlobal) + WORLD_UPWARD_DIRECTION * HEIGHT_ABOVE_HEAD; //--------------------------------------------------------------- // some gl state diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 259483413d..2198977028 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -599,9 +599,6 @@ void LLVivoxVoiceClient::connectorCreate() << "" << mVoiceAccountServerURI << "" << "Normal" << strConnectorHandle - // Voice in multiple instances; by Latif Khalifa - << (gSavedSettings.getBOOL("VoiceMultiInstance") ? "3000050000" : "") - // << "" << "" << logdir << "" << "Connector" @@ -1043,30 +1040,44 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() // cause SLVoice's bind() call to fail with EADDRINUSE. We expect // that eventually the OS will time out previous ports, which is // why we cycle instead of incrementing indefinitely. - // Unfail voice connection failures - //U32 portbase = gSavedSettings.getU32("VivoxVoicePort"); - //static U32 portoffset = 0; - //static const U32 portrange = 100; - //std::string host(gSavedSettings.getString("VivoxVoiceHost")); - //U32 port = portbase + portoffset; - //portoffset = (portoffset + 1) % portrange; - //params.args.add("-i"); - //params.args.add(STRINGIZE(host << ':' << port)); - // - - std::string loglevel = gSavedSettings.getString("VivoxDebugLevel"); - if (loglevel.empty()) - { - loglevel = "0"; - } - params.args.add("-ll"); - params.args.add(loglevel); + static LLCachedControl portbase(gSavedSettings, "VivoxVoicePort"); + static LLCachedControl host(gSavedSettings, "VivoxVoiceHost"); + static LLCachedControl loglevel(gSavedSettings, "VivoxDebugLevel"); + // Strip trailing directory delimiter + //static LLCachedControl log_folder(gSavedSettings, "VivoxLogDirectory"); std::string log_folder = gSavedSettings.getString("VivoxLogDirectory"); + // + static LLCachedControl shutdown_timeout(gSavedSettings, "VivoxShutdownTimeout"); + static const U32 portrange = 100; + static U32 portoffset = 0; + U32 port = 0; - if (log_folder.empty()) + if (LLAppViewer::instance()->isSecondInstance()) { - log_folder = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + // Ideally need to know amount of instances and + // to increment instance_offset on EADDRINUSE. + // But for now just use rand + static U32 instance_offset = portrange * ll_rand(20); + port = portbase + portoffset + instance_offset; + } + else + { + // leave main thread with exclusive port set + port = portbase + portoffset; + } + portoffset = (portoffset + 1) % portrange; + params.args.add("-i"); + params.args.add(STRINGIZE(host() << ':' << port)); + + params.args.add("-ll"); + if (loglevel().empty()) + { + params.args.add("0"); + } + else + { + params.args.add(loglevel); } // Strip trailing directory delimiter @@ -1076,7 +1087,17 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() } // params.args.add("-lf"); - params.args.add(log_folder); + // Strip trailing directory delimiter + //if (log_folder().empty()) + if (log_folder.empty()) + // + { + params.args.add(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "")); + } + else + { + params.args.add(log_folder); + } // set log file basename and .log params.args.add("-lp"); @@ -1092,27 +1113,11 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() LLFile::rename(new_log, old_log); } - std::string shutdown_timeout = gSavedSettings.getString("VivoxShutdownTimeout"); - if (!shutdown_timeout.empty()) + if (!shutdown_timeout().empty()) { params.args.add("-st"); params.args.add(shutdown_timeout); } - - // Voice in multiple instances; by Latif Khalifa - if (gSavedSettings.getBOOL("VoiceMultiInstance")) - { - S32 port_nr = 30000 + ll_rand(20000); - LLControlVariable* voice_port = gSavedSettings.getControl("VivoxVoicePort"); - if (voice_port) - { - voice_port->setValue(LLSD(port_nr), false); - params.args.add("-i"); - params.args.add(llformat("127.0.0.1:%u", gSavedSettings.getU32("VivoxVoicePort"))); - } - } - // - params.cwd = gDirUtilp->getAppRODataDir(); // Check if using the old SLVoice for Linux. the SDK in that version is too old to handle the extra args @@ -1134,9 +1139,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() sGatewayPtr = LLProcess::create(params); - // Unfail voice connection failures - //mDaemonHost = LLHost(host.c_str(), port); - mDaemonHost = LLHost(gSavedSettings.getString("VivoxVoiceHost").c_str(), gSavedSettings.getU32("VivoxVoicePort")); + mDaemonHost = LLHost(host().c_str(), port); } else { diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 5c70de072e..a6efdab747 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5516,6 +5516,10 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, const LLMatrix4* model_mat = NULL; LLDrawable* drawable = facep->getDrawable(); + if(!drawable) + { + return; + } if (rigged) { @@ -5537,8 +5541,9 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, //drawable->getVObj()->setDebugText(llformat("%d", drawable->isState(LLDrawable::ANIMATED_CHILD))); - U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0; - U8 shiny = facep->getTextureEntry()->getShiny(); + const LLTextureEntry* te = facep->getTextureEntry(); + U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? te->getBumpmap() : 0; + U8 shiny = te->getShiny(); LLViewerTexture* tex = facep->getTexture(); @@ -5548,22 +5553,31 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, LLUUID mat_id; - auto* gltf_mat = (LLFetchedGLTFMaterial*) facep->getTextureEntry()->getGLTFRenderMaterial(); - llassert(gltf_mat == nullptr || dynamic_cast(facep->getTextureEntry()->getGLTFRenderMaterial()) != nullptr); + auto* gltf_mat = (LLFetchedGLTFMaterial*)te->getGLTFRenderMaterial(); + llassert(gltf_mat == nullptr || dynamic_cast(te->getGLTFRenderMaterial()) != nullptr); + + // show legacy when editing the fallback materials. + static LLCachedControl showSelectedinBP(gSavedSettings, "FSShowSelectedInBlinnPhong"); + if( gltf_mat && facep->getViewerObject()->isSelected() && showSelectedinBP ) + { + gltf_mat = nullptr; + } + // + if (gltf_mat != nullptr) { mat_id = gltf_mat->getHash(); // TODO: cache this hash - if (!facep->hasMedia()) + if (!facep->hasMedia() || (tex && tex->getType() != LLViewerTexture::MEDIA_TEXTURE)) { // no media texture, face texture will be unused tex = nullptr; } } else { - mat = facep->getTextureEntry()->getMaterialParams().get(); + mat = te->getMaterialParams().get(); if (mat) { - mat_id = facep->getTextureEntry()->getMaterialParams()->getHash(); + mat_id = te->getMaterialParams()->getHash(); } } @@ -5578,7 +5592,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, if (mat) { - BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) || (facep->getTextureEntry()->getColor().mV[3] < 0.999f) ? TRUE : FALSE; + BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) || (te->getColor().mV[3] < 0.999f) ? TRUE : FALSE; if (type == LLRenderPass::PASS_ALPHA) { shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND, is_alpha); @@ -5774,6 +5788,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; llassert(!gCubeSnapshot); + if (group->isDead()) + { + return; + } + if (group->changeLOD()) { group->mLastUpdateDistance = group->mDistance; @@ -5861,7 +5880,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) LLVOVolume* vobj = drawablep->getVOVolume(); - if (!vobj) + if (!vobj || vobj->isDead()) { continue; } @@ -6775,6 +6794,14 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace const LLTextureEntry* te = facep->getTextureEntry(); LLGLTFMaterial* gltf_mat = te->getGLTFRenderMaterial(); + + // show legacy when editing the fallback materials. + static LLCachedControl showSelectedinBP(gSavedSettings, "FSShowSelectedInBlinnPhong"); + if( gltf_mat && facep->getViewerObject()->isSelected() && showSelectedinBP ) + { + gltf_mat = nullptr; + } + // if (hud_group && gltf_mat == nullptr) { //all hud attachments are fullbright diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 3f0da307f2..9f5d0b3a16 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -979,35 +979,27 @@ void LLWearableItemsList::updateList(const LLUUID& category_id) void LLWearableItemsList::updateChangedItems(const uuid_vec_t& changed_items_uuids) { // nothing to update - if (changed_items_uuids.empty()) return; + if (changed_items_uuids.empty()) + return; - typedef std::vector item_panel_list_t; - - item_panel_list_t items; - getItems(items); - - for (item_panel_list_t::iterator items_iter = items.begin(); - items_iter != items.end(); - ++items_iter) + uuid_vec_t::const_iterator uuids_begin = changed_items_uuids.begin(), uuids_end = changed_items_uuids.end(); + pairs_const_iterator_t pairs_iter = getItemPairs().begin(), pairs_end = getItemPairs().end(); + while (pairs_iter != pairs_end) { - LLPanelInventoryListItemBase* item = dynamic_cast(*items_iter); - if (!item) continue; + LLPanel* panel = (*(pairs_iter++))->first; + LLPanelInventoryListItemBase* item = dynamic_cast(panel); + if (!item) + continue; LLViewerInventoryItem* inv_item = item->getItem(); - if (!inv_item) continue; + if (!inv_item) + continue; - LLUUID linked_uuid = inv_item->getLinkedUUID(); - - for (uuid_vec_t::const_iterator iter = changed_items_uuids.begin(); - iter != changed_items_uuids.end(); - ++iter) - { - if (linked_uuid == *iter) - { - item->setNeedsRefresh(true); - break; - } - } + const LLUUID& linked_uuid = inv_item->getLinkedUUID(); + if (std::find(uuids_begin, uuids_end, linked_uuid) != uuids_end) + { + item->setNeedsRefresh(true); + } } } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 1eb86679ee..f8e23347f5 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -107,7 +107,7 @@ #include "llfloaterpathfindingconsole.h" #include "llfloaterpathfindingcharacters.h" #include "llfloatertools.h" -#include "llpanelface.h" +// #include "llpanelface.h" // switchable edit texture/materials panel - include not needed #include "llpathfindingpathtool.h" #include "llscenemonitor.h" #include "llprogressview.h" @@ -1771,17 +1771,23 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) void LLPipeline::removeMutedAVsLights(LLVOAvatar* muted_avatar) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; - for (light_set_t::iterator iter = gPipeline.mNearbyLights.begin(); - iter != gPipeline.mNearbyLights.end(); iter++) - { - const LLViewerObject *vobj = iter->drawable->getVObj(); - if (vobj && vobj->getAvatar() - && vobj->isAttachment() && vobj->getAvatar() == muted_avatar) - { - gPipeline.mLights.erase(iter->drawable); - gPipeline.mNearbyLights.erase(iter); - } - } + light_set_t::iterator iter = gPipeline.mNearbyLights.begin(); + while (iter != gPipeline.mNearbyLights.end()) + { + const LLViewerObject* vobj = iter->drawable->getVObj(); + if (vobj + && vobj->getAvatar() + && vobj->isAttachment() + && vobj->getAvatar() == muted_avatar) + { + gPipeline.mLights.erase(iter->drawable); + iter = gPipeline.mNearbyLights.erase(iter); + } + else + { + iter++; + } + } } U32 LLPipeline::addObject(LLViewerObject *vobj) @@ -3654,7 +3660,9 @@ void LLPipeline::postSort(LLCamera &camera) if (!gNonInteractive) { - LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit()); + // switchable edit texture/materials panel + // LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit()); + LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getTextureChannelToEdit()); } // Draw face highlights for selected faces. @@ -8574,7 +8582,7 @@ void LLPipeline::doWaterHaze() else { //render water patches like LLDrawPoolWater does - LLGLDepthTest depth(GL_FALSE); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); LLGLDisable cull(GL_CULL_FACE); gGLLastMatrix = NULL; diff --git a/indra/newview/skins/ansastorm/xui/en/sidepanel_appearance.xml b/indra/newview/skins/ansastorm/xui/en/sidepanel_appearance.xml index cf76ace7be..01421f6099 100644 --- a/indra/newview/skins/ansastorm/xui/en/sidepanel_appearance.xml +++ b/indra/newview/skins/ansastorm/xui/en/sidepanel_appearance.xml @@ -108,8 +108,7 @@ width="415"> top="6" width="24" /> - + @@ -1077,6 +1078,8 @@ with the same filename but different name + + diff --git a/indra/newview/skins/default/xui/az/floater_beacons.xml b/indra/newview/skins/default/xui/az/floater_beacons.xml index 569d019fcb..35be748764 100644 --- a/indra/newview/skins/default/xui/az/floater_beacons.xml +++ b/indra/newview/skins/default/xui/az/floater_beacons.xml @@ -20,7 +20,7 @@ - + Göstərmə istiqaməti: diff --git a/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml index 863f3de86e..e7b294d810 100644 --- a/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml @@ -20,7 +20,7 @@ - + diff --git a/indra/newview/skins/default/xui/az/notifications.xml b/indra/newview/skins/default/xui/az/notifications.xml index 9adbebf57b..326552c1a1 100644 --- a/indra/newview/skins/default/xui/az/notifications.xml +++ b/indra/newview/skins/default/xui/az/notifications.xml @@ -3738,7 +3738,7 @@ Siz [TIME] saniyədən sonra '[BODYREGION]' üçün [RESOLUTION] bişmiş tekstu Siz [TIME] saniyədən sonra '[BODYREGION]' üçün [RESOLUTION] bişmiş teksturasını yerli olaraq yenilədiniz. - Teksturanı yükləmək mümkün deyil. + Teksturanı yükləmək mümkün deyil: '[NAME]' [REASON] diff --git a/indra/newview/skins/default/xui/az/panel_preferences_sound.xml b/indra/newview/skins/default/xui/az/panel_preferences_sound.xml index 59fa3606c3..7ea84d21e5 100644 --- a/indra/newview/skins/default/xui/az/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/az/panel_preferences_sound.xml @@ -98,7 +98,6 @@ Avtomatik oxutma + + + V + + + + + + + + + + + + + + Offset + + + + U + + + + + + + + V + + + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + + Scale + + + + U + + + + + + + + + + V + + + + + + + + + + + + + + Offset + + + + U + + + + + + + + V + + + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + Scale + + + + U + + + + + + + + + + V + + + + + + + + + + + + + + Offset + + + + U + + + + + + + + V + + + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + Scale + + + + U + + + + + + + + + + V + + + + + + + + + + + + + + Offset + + + + U + + + + + + + + V + + + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + Scale + + + + U + + + + + + + + + + V + + + + + + + + + + + + + + Offset + + + + U + + + + + + + + V + + + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + % + + + + Alpha mode + + + + + + + + + + + + + Bumpiness + + + + + + + + + + + + + + + + + + + + + + + + + + + + Shininess + + + + + + + + + + + + + + + + + + + + + + + + + Scale + + + + H + + + + + + + + V + + + + + + + + + + + + Offset + + + + H + + + + + + V + + + + + + + + + + Rotation + + + + + + + + + + + + + + Scale + + + + H + + + + + + + + V + + + + + + + + + + + + Offset + + + + H + + + + + + V + + + + + + + + + + Rotation + + + + + + + + + + + + + + Scale + + + + H + + + + + + + + V + + + + + + + + + + + + Offset + + + + H + + + + + + V + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + URL of chosen media, if any, goes here + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Please wait @@ -136,7 +137,7 @@ layout="topleft" left_delta="0" name="bar0" - top_delta="-2" + top_delta="-5" width="20" /> + + Disabled + +